Сетка в двух измерениях: макет страницы, галереи, каталоги
frFlexbox раскладывает элементы в одну линию. Grid — сразу по строкам и колонкам. display: grid на контейнере и grid-template-columns со списком ширин колонок — и дети встают по ячейкам слева направо, строка за строкой:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>Grid</title>
<style>
body { font-family: Arial, sans-serif; }
.grid {
display: grid;
grid-template-columns: 120px 1fr 2fr;
gap: 8px;
}
.grid div { padding: 10px; background: #1967d2; color: white; }
</style>
</head>
<body>
<div class="grid">
<div>120px</div>
<div>1fr</div>
<div>2fr</div>
<div>4</div>
<div>5</div>
<div>6</div>
</div>
</body>
</html>

fr — доля свободного места: после того как первая колонка забрала 120px, остаток делится на три доли, вторая колонка получает одну, третья — две. Строки создаются сами, сколько нужно для всех элементов. Промежутки — тот же gap, что во Flexbox.
| Запись | Колонки |
|---|---|
1fr 1fr 1fr или repeat(3, 1fr) | Три равные |
240px 1fr | Боковая колонка фиксированной ширины и основная |
minmax(200px, 1fr) | Не уже 200px, иначе доля места |
repeat(auto-fit, minmax(140px, 1fr)) | Столько колонок не уже 140px, сколько помещается |
Самая полезная строка модуля: repeat(auto-fit, minmax(140px, 1fr)). Браузер сам считает, сколько колонок шириной не меньше 140px помещается, и делит место поровну. Галерея:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>Галерея</title>
<style>
*, *::before, *::after { box-sizing: border-box; }
body { margin: 0; padding: 12px; font-family: Arial, sans-serif; }
.gallery {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
gap: 10px;
}
.photo {
aspect-ratio: 4 / 3;
display: flex;
align-items: center;
justify-content: center;
background: #b0bec5;
border-radius: 6px;
}
</style>
</head>
<body>
<div class="gallery">
<div class="photo">1</div>
<div class="photo">2</div>
<div class="photo">3</div>
<div class="photo">4</div>
<div class="photo">5</div>
</div>
</body>
</html>


В отличие от ряда карточек на Flexbox (модуль 06), последняя плитка не растянулась на всю строку: колонки сетки одинаковы во всех строках. aspect-ratio: 4 / 3 держит пропорции плитки при любой ширине — так же ведут себя фотографии. Значение auto-fill вместо auto-fit оставляет пустые колонки, если элементов мало, а auto-fit растягивает имеющиеся.
Элемент может занять несколько колонок или строк. Линии сетки пронумерованы с 1 слева, с −1 справа:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>Объединение ячеек</title>
<style>
body { font-family: Arial, sans-serif; }
.grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-auto-rows: 50px;
gap: 6px;
}
.grid div { padding: 6px; background: #b0bec5; }
.grid .wide { grid-column: span 2; background: #1967d2; color: white; }
.grid .tall { grid-row: span 2; background: #2e7d32; color: white; }
.grid .full { grid-column: 1 / -1; background: #6a1b9a; color: white; }
</style>
</head>
<body>
<div class="grid">
<div class="full">grid-column: 1 / -1</div>
<div class="wide">span 2</div>
<div class="tall">row span 2</div>
<div>4</div>
<div>5</div>
<div>6</div>
<div>7</div>
</div>
</body>
</html>

| Запись | Смысл |
|---|---|
grid-column: span 2 | Занять две колонки, начиная с текущего места |
grid-row: span 2 | Занять две строки |
grid-column: 1 / -1 | От первой линии до последней — всю ширину сетки |
grid-column: 2 / 4 | От второй линии до четвёртой — колонки 2 и 3 |
grid-auto-rows: 50px задаёт высоту строк, которые сетка создаёт сама. Остальные элементы заполнили свободные ячейки по порядку: в третьей строке ячейку под зелёным блоком браузер пропустил — она уже занята, и элемент 7 встал в последнюю колонку.
grid-template-areas рисует макет прямо в CSS: каждая строка в кавычках — строка сетки, слова — имена областей. Элементу остаётся указать grid-area:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>Макет страницы</title>
<style>
*, *::before, *::after { box-sizing: border-box; }
body {
margin: 0;
min-height: 100vh;
display: grid;
grid-template-columns: 160px 1fr;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"header header"
"nav main"
"footer footer";
font-family: Arial, sans-serif;
}
header { grid-area: header; background: #1967d2; }
nav { grid-area: nav; background: #e3f2fd; }
main { grid-area: main; }
footer { grid-area: footer; background: #37474f; }
header, footer { color: white; }
body > * { padding: 10px 14px; }
</style>
</head>
<body>
<header>Шапка</header>
<nav>Меню разделов</nav>
<main>
<h1>Основное содержимое</h1>
<p>Расположение блоков описано картой областей в CSS.</p>
</main>
<footer>Подвал</footer>
</body>
</html>

Одинаковые имена подряд объединяют ячейки: "header header" — шапка на обе колонки. grid-template-rows: auto 1fr auto — шапка и подвал по высоте содержимого, середина забирает остальное; вместе с min-height: 100vh это ещё один способ прижать подвал к низу. Порядок элементов в HTML остаётся логичным (шапка, меню, содержимое, подвал), а расположение задаёт CSS. Перестроить макет для телефона — значит переписать одну карту областей в медиазапросе (модуль 08).
| Задача | Инструмент | Почему |
|---|---|---|
| Пункты меню, кнопки в строку, иконка рядом с текстом | Flexbox | Одна линия, размеры по содержимому |
| Центрирование одного блока | Flexbox или Grid | place-items: center в Grid ещё короче |
| Каталог, галерея, плитки одного размера | Grid | Колонки одинаковы во всех строках |
| Макет страницы: шапка, колонки, подвал | Grid | Две оси сразу, карта областей |
| Карточки разной ширины, переносятся по содержимому | Flexbox | Каждый элемент сам решает свой размер |
Они не соперники и часто вложены друг в друга: страница — Grid, шапка внутри неё — Flexbox, сетка товаров — Grid, содержимое карточки товара — снова Flexbox. Оба инструмента поддерживаются всеми браузерами, которыми сейчас пользуются.
В инструментах разработчика рядом с элементом, у которого display: grid, в дереве Elements стоит значок grid. Щелчок по нему накладывает на страницу линии сетки с номерами — видно, где проходят колонки и почему элемент оказался не там. Для flex-контейнеров есть такой же значок flex.
display: grid поставили элементам, а не контейнеру.% вместе с gap дают горизонтальную прокрутку: 3 × 33% + промежутки больше 100%. Используйте fr.1fr распирает колонку: minmax(0, 1fr) разрешает ей быть уже содержимого.display: grid + grid-template-columns — сетка; строки создаются самиfr — доля свободного места; колонки — в fr, а не в %repeat(auto-fit, minmax(Npx, 1fr)) — адаптивная сетка без медиазапросовgrid-column: span 2 и 1 / -1 — объединение ячеекgrid-template-areas — макет страницы картой; HTML остаётся в логическом порядке