Как �вер�тать Bento-галерею на CSS Grid

Эта �тать� о�нована на одном из практиче�ких заданий verstaem.online.

Вы можете читать материал как обычное руковод�тво или �начала попробовать выполнить задание �амо�то�тельно, а затем �равнить �вое решение � подробным разбором.

Перейти к заданию

В �той �татье мы �оздадим �овременную Bento-галерею � карточками разных размеров. �а ее примере познакомим�� � более продвинутыми возможно�т�ми CSS Grid, научим�� объедин�ть колонки, делать карточки � изображени�ми и затемнением, а также разберем, как �тро�т�� подобные интерфей�ы, которые �егодн� можно в�третить практиче�ки в каждом �овременном приложении.

К�тати, почему «bento»? �азвание пришло из �пон�ких бенто-бок�ов, где разные продукты разложены по �екци�м разных размеров. Соб�твенно, в нашем дизайне похожа� и�тори�.

Создаем HTML-разметку

Сначала �оздадим базовую HTML-разметку � помощью Emmet. Дл� �того до�таточно вве�ти ! и нажать Tab. Обратите внимание на атрибут lang. По�кольку о�новной контент �траницы напи�ан на ру��ком �зыке, зде�ь и�пользуем значение ru.

<!doctype html>
<html lang="ru">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Bento-галере�</title>
  </head>
  <body>
  </body>
</html>

Итак, давайте разберем�� � базовой разметкой. Сделаем див, а в нем контейнер, чтобы выровн�ть в�е по центру. Мы �разу �юда добавл�ем кла�� grid, чтобы управл�ть �еткой.

<div class="content">
    <div class="container grid">

    </div>
</div>

Лева� колонка

Слева ра�полагаем колонку � помощью aside, и добавим внутрь три о�новных �лемента — заголовок, опи�ание, и �пи�ок тегов. Обратите внимание, что emoji в браузере не �овпадают � теми, что в макете. Это нормально, ничего �трашного.

<aside class="content__aside">
  <h1 class="content__title">
    Откройте природу
  </h1>
  <p class="content__descr">
    Про�матривайте ме�та, отобранные фотографами �о в�его мира. И��ледуйте горы, ле�а, пл�жи и города.
  </p>
  <div class="content__tags">
    <div class="content__tag">
      � Горы
    </div>
    <div class="content__tag">
      🌊 Океан
    </div>
    <div class="content__tag">
      🌲 Ле�
    </div>
    <div class="content__tag">
      � Города
    </div>
    <div class="content__tag">
      🌵 Пу�тын�
    </div>
  </div>
</aside>

Теги можно было бы �делать �пи�ком, но �ти �лементы не имеют интерактивно�ти, по�тому �то можно о�тавить через <div>.

Галере�

� вот галерею логично �делать именно �пи�ком. Спи�ок будет управл�ть ра�положением �лементов, а внутри будут карточки, �делаем их � помощью <div>. Внутри карточки будет картинка, название и опи�ание.

<div class="content__gallery">
  <ul class="gallery">
    <li class="gallery__item gallery__item--big">
      <div class="gallery-card">
        <img src="img/1.png" aria-hidden="true" alt="" class="gallery-card__pic">
        <h2 class="gallery-card__title">
          Швейцар�кие альпы
        </h2>
        <p class="gallery-card__descr">
          42 фотографии
        </p>
      </div>
    </li>
    <li class="gallery__item">
      <div class="gallery-card">
        <img src="img/2.png" aria-hidden="true" alt="" class="gallery-card__pic">
        <h2 class="gallery-card__title">
          Океан
        </h2>
        <p class="gallery-card__descr">
          18 фотографий
        </p>
      </div>
    </li>
    <li class="gallery__item">
      <div class="gallery-card">
        <img src="img/3.png" aria-hidden="true" alt="" class="gallery-card__pic">
        <h2 class="gallery-card__title">
          Ле�
        </h2>
        <p class="gallery-card__descr">
          27 фотографий
        </p>
      </div>
    </li>
    <li class="gallery__item">
      <div class="gallery-card">
        <img src="img/4.png" aria-hidden="true" alt="" class="gallery-card__pic">
        <h2 class="gallery-card__title">
          Токио
        </h2>
        <p class="gallery-card__descr">
          31 фотографи�
        </p>
      </div>
    </li>
    <li class="gallery__item">
      <div class="gallery-card">
        <img src="img/5.png" aria-hidden="true" alt="" class="gallery-card__pic">
        <h2 class="gallery-card__title">
          Пл�ж
        </h2>
        <p class="gallery-card__descr">
          15 фотографий
        </p>
      </div>
    </li>
    <li class="gallery__item gallery__item--big">
      <div class="gallery-card">
        <img src="img/6.png" aria-hidden="true" alt="" class="gallery-card__pic">
        <h2 class="gallery-card__title">
          Река
        </h2>
        <p class="gallery-card__descr">
          56 фотографий
        </p>
      </div>
    </li>
    <li class="gallery__item gallery__item--big">
      <div class="gallery-card">
        <img src="img/7.png" aria-hidden="true" alt="" class="gallery-card__pic">
        <h2 class="gallery-card__title">
          Пу�тын�
        </h2>
        <p class="gallery-card__descr">
          13 фотографий
        </p>
      </div>
    </li>
    <li class="gallery__item gallery__item--big">
      <div class="gallery-card">
        <img src="img/8.png" aria-hidden="true" alt="" class="gallery-card__pic">
        <h2 class="gallery-card__title">
          Снег
        </h2>
        <p class="gallery-card__descr">
          28 фотографий
        </p>
      </div>
    </li>
  </ul>
</div>

�е�мотр� на то, что � в�егда обращаю ваше внимание на заполнение alt, зде�ь он не заполнен. В�е потому, что изображени� зде�ь �лужат как декоратив, как фон. И можно было бы �делать их именно через CSS, но � решил показать �по�об через html. Это не ошибка, �то про�то иное мышление. И зде�ь нам пригодит�� атрибут aria-hidden, чтобы �кринридеры не читали �то изображение, а вообще не замечали его. Также обратите внимание, что у некоторых <li> е�ть дополнительный кла�� gallery__item--big, он как раз нужен, чтобы разме�тить �лементы в �етке так, как нам нужно.

Добавл�ем �тили

Подключим файл �тилей через <link> и зададим не�колько базовых правил. Дл� �того задани� до�таточно переопределить box-sizing, �бро�ить от�туп у <body> и подключить шрифт Inter, который и�пользует�� в макете.

* {
  box-sizing: border-box;
}

@font-face {
  font-family: "Inter";
  src: url("../fonts/InterRegular.woff2");
  font-display: swap;
  font-weight: 400;
}

@font-face {
  font-family: "Inter";
  src: url("../fonts/InterBold.woff2");
  font-display: swap;
  font-weight: 700;
}

body {
  margin: 0;
  padding: 20px;
  background: #f4f6f9;
  font-family: "Inter", sans-serif;
}

.container {
  margin: 0 auto;
  padding: 0 15px;
  max-width: 1318px;
}

.grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  align-items: start;
  gap: 20px;
}

Зде�ь мы добавл�ем контейнер дл� центрировани� контента, а также добавл�ем grid, чтобы управл�ть �еткой. Указываем `repeat (12, 1fr) — в�е потому, что в нашем макете так и е�ть — 12 колонок. Это �воего рода �тандарт инду�трии, 12 колонок — �амое удобное чи�ло, которое делит�� на 1, 2, 3, 4, 6, 12. � вот говорить �лементам, �колько колонок им занимать, мы будем ниже.

Стили левой ча�ти

Зададим �тили �разу дл� левой колонки. Зде�ь в�е до�таточно �тандартно, выдел�ем только одну запи�ь — grid-column: 4 span. Зде�ь мы задаем то количе�тво колонок, которое должна занимать лева� ча�ть, из 12ти. Она будет занимать 4 колонки.

.content__aside {
  grid-column: 4 span;
  border-radius: 32px;
  padding: 32px;
  background: #fff;
}

.content__title {
  margin: 0;
  margin-bottom: 20px;
  font-weight: 700;
  font-size: 48px;
  line-height: 120%;
  color: #111827;
}

.content__descr {
  margin: 0;
  margin-bottom: 32px;
  font-weight: 400;
  font-size: 16px;
  line-height: 140%;
  color: #6b7280;
}

.content__tags {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.content__tag {
  border-radius: 100px;
  padding: 8px 12px;
  font-weight: 400;
  font-size: 12px;
  line-height: 120%;
  color: #111827;
  background: #f3f4f6;
}

Стили правой ча�ти

Зде�ь в�е �ложнее и интере�нее. Конечно, нужно �делать размер дл� правой ча�ти через �вой grid-column. �о тут е�ть другой интере�ный момент — нам нужно �делать �етку и дл� �амого �пи�ка карточек. По�тому мы �нова и�пользуем grid, но уже � 8-ю колонками.

.content__gallery {
  grid-column: 8 span;
}

.gallery {
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  margin: 0;
  padding: 0;
  list-style: none;
  gap: 20px;
}

Конечно, тут можно было по�тавить и 12, но е�ли в макете 8 — зачем у�ложн�ть? Далее, нам нужно ра�положить �лементы. Большее количе�тво карточек занимают 2 колонки, и лишь некоторые — 4. Так и укажем.

.gallery__item {
  grid-column: 2 span;
}

.gallery__item--big {
  grid-column: 4 span;
}

Стили карточки

Теперь о�тает�� дело техники — про�то раздать �тили �лементам карточки. �о разумеет��, без нюан�ов тут не обойдет��.

.gallery-card {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  overflow: hidden;
  border-radius: 24px;
  padding: 16px;
  min-height: 200px;
  background: #fff;
}

Дл� начала �кажем, что зде�ь задан overflow: hidden, чтобы изображение обрезало�ь и принимало тот же радиу�, что и у родител�. Также зде�ь �вно указан flexbox и justify-content: flex-end. Таким образом мы прижимаем ве�ь контент карточки к нижнему краю, пр�мо как в макете.

В итоге получает�� кла��иче�ка� �итуаци� — Grid управл�ет «большой» �еткой, а Flex — внутренно�т�ми. Это очень ча�то прои�ходит в реальных макетах.

Далее �делаем затемнение, и зде�ь пригодит�� в�е то же правило, что и раньше — е�ли мы можем делать декор без вмешатель�тва в html, нужно так и делать. По�тому и�пользуем п�евдо�лемент. О�обое внимание обратите на inset: 0 и z-index: 1. Один ра�т�гивает п�евдо�лемент на в�ю карточку, второй поднимает ее на �лой выше. Это нужно, чтобы изображение было «под» затемнением.

.gallery-card::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: linear-gradient(180deg, rgba(217, 217, 217, 0) 0%, rgba(0, 0, 0, 0.9) 100%);
}

Далее �амо изображение. Размещаем мы его также через position: absolute, чтобы оно в�тало именно как фон и не вли�ло на размеры карточки. Вли�ть на размеры в�егда должен контент. Ра�т�гиваем также через inset и картинка в�тает так, будто �то фон.

.gallery-card__pic {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: inherit;
}

Теперь �тили тек�та. Тут в�е про�то, забираем в�е из макета. �о не забудем добавить position: relative и z-index: 2, именно 2, чтобы тек�т был еще выше, чем затемнение.

.gallery-card__title {
  position: relative;
  z-index: 2;
  margin: 0;
  margin-bottom: 4px;
  font-weight: 700;
  font-size: 16px;
  color: #fff;
}

.gallery-card__descr {
  position: relative;
  z-index: 2;
  margin: 0;
  font-weight: 400;
  font-size: 12px;
  color: rgba(255, 255, 255, 0.8);
}

Теперь вы умеете �оздавать Bento-галереи � помощью CSS Grid. Мы научили�ь �троить �ложные �етки, объедин�ть колонки, работать � карточками поверх изображений, и�пользовать п�евдо�лементы дл� затемнени� и �оздавать �овременный интерфей�, который легко ма�штабирует�� и выгл�дит профе��ионально.

Решение задачи

предыдущий по�т �ледующий по�т