Мне нужно сделать такой макет:
Как видите, изображение героя «смещено», а фон короче. Мне удалось сделать это с помощью вложенных CSS-сеток и «фиктивного» элемента для добавления фона, но мне было интересно, есть ли более разумные способы, чем использование фиктивного элемента... Я публикую код, потому что этот встроенный редактор, похоже, неправильно отображает код, который я использовал. Я прокомментировал все это, чтобы объяснить важные моменты.
https://codepen.io/stratboy/pen/YzbbXVa
Stackoverflow вынуждает меня написать некоторый код. Вот немного HTML:
<div class = "wrapper">
<div class = "container">
<div class = "bg">
</div>
<div class = "child">
<div class = "offset image">offset</div>
<div class = "text">Lorem Ipsum</div>
</div>
</div>
</div>
И (S)CSS:
.wrapper{ // just to simulate real website
width: 1200px;
margin: 0 auto;
}
.container{ // main grid
display: grid;
grid-template-rows: 80px auto 120px;
grid-template-columns: 1fr;
// full width
margin-left: calc(-50vw + 50%);
margin-right: calc(-50vw + 50%);
}
.bg{ // dummy element for background
background-color: teal;
grid-row: 1 / 3;
grid-column: 1 / 2;
}
.child{
width: 1200px;
margin: 0 auto;
grid-row: 2 / 4; // offset for simulated padding
grid-column: 1 / 2;
display: grid; // it is a grid itself, so I can offset the "image"
grid-template-rows: 1fr 120px;
grid-template-columns: 50% 50%;
}
.offset.image{
grid-column: 1 / 2;
grid-row: 1 / 3;
background-color: cyan;
}
.text{
grid-column: 2 / 3; // restrict to first 2 rows to create the image offset
grid-row: 1 / 2;
background-color: green;
padding-bottom: 80px; // just to test
}
Не могли бы вы просто использовать псевдоэлемент, чтобы создать фон, доходящий только до выступа? Это самый простой способ, который я могу придумать
.content {
position: relative;
display: grid;
grid-template-columns: 2fr 1fr;
--overhang: 2rem;
}
.content::after {
content: "";
position: absolute;
inset: 0 0 var(--overhang) 0;
background-color: #F0EEE9;
z-index: 2;
}
.text, .image {
z-index: 3;
padding: 0.5rem;
}
.text {
padding-bottom: var(--overhang); /* just make sure the text doesn't encroach over the overhung region */
}
<div class = "content">
<div class = "image">
<img src='https://picsum.photos/id/237/300/200'>
</div>
<div class = "text">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam orci ex, ullamcorper id ultrices vel, lacinia ut elit. Maecenas at justo a mauris cursus
</div>
</div>
Просто используйте линейный градиент, который останавливается на определенном расстоянии от нижней части содержащего элемента.
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
div {
height: 90vh;
padding: 20px;
background-image:
linear-gradient(to bottom, pink calc(100% - 50px), transparent calc(100% - 50px));
}
img {
height: 100%;
width: auto;
}
<div>
<img src = "https://images.unsplash.com/photo-1717496001989-0a0f32386d12?crop=entropy&cs=srgb&fm=jpg&ixid=M3wzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE3MTk1NzU3MzR8&ixlib=rb-4.0.3&q=85" alt = "">
</div>
Как показывает этот пост, существует очень много способов сделать такие вещи с помощью CSS. Не существует лучших решений, но некоторые из них могут лучше всего соответствовать вашим потребностям.
Некоторыми решениями могут быть фоновое изображение, клип-путь, сложные сетки, переполнение, абсолютное/относительное позиционирование, градиентный фон...
Вот пример простого переполнения. Недостатком является то, что вам понадобится какое-то поле для элементов ниже.
.fake-image {
width: 200px;
margin-top: 3rem;
aspect-ratio: 2;
background: red;
}
.grid {
justify-items: center;
display: grid;
grid-template-columns: 50% 50%;
grid-template-rows: 10rem;
background-color: pink;
overflow: visible /* not needed */
}
<div class = "grid">
<div class = "fake-image"></div>
<div>
<h3>page title</h3>
<p> Some longer content </p>
</div>
</div>
<div>
Here is some text that wil appear under the picture
</div>
Вот еще один подход, использующий преобразования, некоторые (базовые) вычисления и отрицательный запас. Также полностью отзывчивый.
section {
/* define your desired paddings */
--h-padding: 2rem;
--v-padding: 2rem;
/* define your desired offset for this section */
--offset: 3rem;
}
section .inner {
background: teal;
padding: var(--v-padding) var(--h-padding);
display: grid;
grid-template-columns: 1fr;
gap: 2rem;
}
.hero img {
vertical-align: top;
object-fit: cover;
width: 100%;
height: 100%;
}
@media screen and (min-width: 80ch) {
section {
/* add offset to bottom padding to extend the box model - this prevents overlapping with following elements */
padding-bottom: var(--offset);
}
section .inner {
grid-template-columns: 2fr 1fr;
gap: 4rem;
}
.hero {
/* pull hero container up */
margin-top: calc((var(--offset) + var(--v-padding)) * -1);
}
.hero img {
/* move your image down by applying the offset transform */
transform: translateY(calc(var(--offset) + var(--v-padding)));
}
}
/* demo css */
html {
box-sizing: border-box;
}
*,
*::after,
*::before {
box-sizing: inherit;
}
.content p:first-child {
margin-top: 0;
}
<section>
<div class = "inner">
<div class = "hero">
<img src = "https://picsum.photos/800/450" alt = "heroimage" />
</div>
<div class = "content">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam orci ex, ullamcorper id ultrices vel, lacinia ut elit. Maecenas at justo a mauris cursus</p>
</div>
</div>
</section>
комментарии с
//
недопустимы в CSS, вам придется использовать/* */