Как �вер�тать 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. Мы научили�ь �троить �ложные �етки, объедин�ть колонки, работать � карточками поверх изображений, и�пользовать п�евдо�лементы дл� затемнени� и �оздавать �овременный интерфей�, который легко ма�штабирует�� и выгл�дит профе��ионально.