Более разумный способ «сместить» элемент из его контейнера (с фоном)?

Мне нужно сделать такой макет:

Как видите, изображение героя «смещено», а фон короче. Мне удалось сделать это с помощью вложенных 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
    }

комментарии с // недопустимы в CSS, вам придется использовать /* */

Temani Afif 28.06.2024 12:37
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Введение в CSS
Введение в CSS
CSS является неотъемлемой частью трех основных составляющих front-end веб-разработки.
Как выровнять Div по центру?
Как выровнять Div по центру?
Чтобы выровнять элемент <div>по горизонтали и вертикали с помощью CSS, можно использовать комбинацию свойств и значений CSS. Вот несколько методов,...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
Toor - Ангулярный шаблон для бронирования путешествий
Toor - Ангулярный шаблон для бронирования путешествий
Toor - Travel Booking Angular Template один из лучших Travel & Tour booking template in the world. 30+ валидированных HTML5 страниц, которые помогут...
0
1
59
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Не могли бы вы просто использовать псевдоэлемент, чтобы создать фон, доходящий только до выступа? Это самый простой способ, который я могу придумать

.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>

Другие вопросы по теме