Grid
Flexbox выстраивает элементы вдоль одной линии. Grid (сетка) раскладывает их сразу по двум направлениям — по строкам и колонкам, как в таблице. Он подходит для галерей, карточек товаров и общего каркаса страницы.
Колонки
display: grid превращает родителя в grid-контейнер, а grid-template-columns перечисляет ширину колонок. Дочерние элементы сами заполняют ячейки слева направо, а когда колонки кончаются — переходят на следующую строку:
<style>
.grid { display: grid; grid-template-columns: 100px 100px 100px; }
.grid div { padding: 12px; background: lavender; border: 1px solid mediumpurple; }
</style>
<div class="grid">
<div>1</div><div>2</div><div>3</div>
<div>4</div><div>5</div><div>6</div>
</div>Три значения — три колонки по 100 пикселей. Шесть элементов заняли две строки.
Доли свободного места
Единица fr (от fraction — доля) делит свободное место на части. Три колонки по 1fr — три равные части ширины. gap задаёт промежутки между ячейками, как во flexbox:
<style>
.grid { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 8px; }
.grid div { padding: 12px; background: lightskyblue; }
</style>
<div class="grid">
<div>1</div><div>2</div><div>3</div>
</div>Запись 2fr 1fr сделала бы первую колонку вдвое шире второй.
repeat и смешанные размеры
Функция repeat(4, 1fr) — короткая запись четырёх одинаковых колонок. Фиксированные размеры и доли можно сочетать: колонка в пикселях берёт своё, а 1fr — остаток:
<style>
.page { display: grid; grid-template-columns: 120px 1fr; gap: 8px; margin-bottom: 8px; }
.four { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; }
.page div, .four div { padding: 12px; background: honeydew; }
</style>
<div class="page"><div>Меню</div><div>Содержимое занимает остаток</div></div>
<div class="four"><div>1</div><div>2</div><div>3</div><div>4</div></div>Строки
Высоту строк задаёт grid-template-rows. Если строк больше, чем описано, лишние получают высоту из grid-auto-rows:
<style>
.grid { display: grid; grid-template-columns: repeat(3, 1fr); grid-auto-rows: 60px; gap: 8px; }
.grid div { padding: 8px; background: lightyellow; }
</style>
<div class="grid">
<div>1</div><div>2</div><div>3</div><div>4</div><div>5</div>
</div>Без grid-auto-rows строка была бы высотой по содержимому.
Адаптивная сетка
Функция minmax(120px, 1fr) задаёт колонку не уже 120 пикселей и не шире одной доли. Вместе с repeat(auto-fill, ...) браузер сам решает, сколько колонок поместится:
<style>
.cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap: 8px; }
.cards div { padding: 20px 12px; background: mistyrose; text-align: center; }
</style>
<div class="cards">
<div>1</div><div>2</div><div>3</div><div>4</div><div>5</div><div>6</div><div>7</div>
</div>Окно примера растягивается вместе со страницей. Сузьте окно браузера — колонок станет меньше, а карточки останутся не уже 120 пикселей.
Grid или flexbox
| Задача | Что выбрать |
|---|---|
| Элементы в одну линию: меню, кнопки | Flexbox |
| Сетка из строк и колонок: карточки, галерея | Grid |
| Каркас страницы: шапка, меню, контент | Grid |
| Выровнять содержимое внутри блока | Flexbox |
Их часто используют вместе: grid — для сетки карточек, flexbox — внутри каждой карточки. А чтобы части соседних карточек встали на одни линии, внутренняя сетка может взять строки у внешней — об этом урок «Subgrid».
Частая ошибка
Колонки в процентах вместе с gap вылезают за контейнер: три колонки по 33% и два промежутка по 16px в сумме больше 100%. Единица fr делит место, которое осталось после промежутков:
<style>
.grid { display: grid; gap: 16px; margin-bottom: 8px; border: 2px dashed gray; }
.bad { grid-template-columns: 33% 33% 33%; }
.ok { grid-template-columns: repeat(3, 1fr); }
.grid div { padding: 12px; background: lavender; }
</style>
<div class="grid bad"><div>33%</div><div>33%</div><div>33%</div></div>
<div class="grid ok"><div>1fr</div><div>1fr</div><div>1fr</div></div>Верхняя сетка выходит за пунктирную рамку, нижняя помещается точно.