CSS Grid Layout — это модуль CSS для двумерной раскладки: элемент с display: grid делит свое пространство на строки и столбцы одновременно, а его прямые потомки занимают ячейки или области этой сетки. Ниже — рабочий макет страницы, единица fr, адаптивная сетка без медиазапросов, области, выравнивание, отличие от Flexbox и subgrid.
Содержание
- Словарь: пять терминов, которые путают
- Минимальный полный пример: макет страницы
- Столбцы и единица fr
- Адаптивные карточки без медиазапросов
- Размещение по линиям
- Области и их правила
- Отступы: gap
- Выравнивание
- Grid или Flexbox
- Вложенная сетка и subgrid
- Если не получилось
- Выводы
- Где применяется / связь с практикой
- FAQ
Все размеры в примерах — из прогона в Google Chrome 153 (headless) 23 сентября 2026 года: координаты элементов снимались через getBoundingClientRect().
Словарь: пять терминов, которые путают
| Термин | Что это |
|---|---|
| Контейнер | Элемент с display: grid (или inline-grid) |
| Элемент сетки | Только ПРЯМОЙ потомок контейнера; внуки в сетке не участвуют |
| Линия | Граница между треками; у 3 столбцов 4 вертикальные линии, нумерация с 1 |
| Трек | Строка или столбец целиком |
| Область | Прямоугольник из соседних ячеек, в том числе именованный |
Сетка, заданная свойствами grid-template-*, называется явной. Если элементов больше, чем ячеек, браузер достраивает неявные треки, их размер задают grid-auto-rows и grid-auto-columns.
Минимальный полный пример: макет страницы
Сохраните как index.html и откройте в браузере:
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<style>
body { margin: 0; }
.page {
display: grid;
grid-template-columns: 200px 1fr;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"header header"
"sidebar main"
"footer footer";
gap: 16px;
min-height: 100vh;
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.footer { grid-area: footer; }
.page > * { background: #eef; padding: 12px; }
@media (max-width: 600px) {
.page {
grid-template-columns: 1fr;
grid-template-areas: "header" "main" "sidebar" "footer";
}
}
</style>
</head>
<body>
<div class="page">
<header class="header">Шапка</header>
<nav class="sidebar">Меню</nav>
<main class="main">Контент</main>
<footer class="footer">Подвал</footer>
</div>
</body>
</html>
При ширине окна 1000px меню получает ровно 200px, контент — 784px (1000 — 200 — 16 на зазор), шапка и подвал тянутся на всю ширину, а средняя строка 1fr забирает всю высоту, оставшуюся от шапки и подвала. При ширине 500px сетка становится одной колонкой, и контент встает выше меню.
Разбор по строкам:
grid-template-columnsиgrid-template-rowsзадают размеры треков через пробел.grid-template-areasрисует карту областей строками в кавычках, аgrid-areaу элемента ставит его в область с этим именем.gap— зазор между треками, у краев контейнера его нет.
Важная граница: сетка меняет только визуальный порядок. Клавиатура и скринридер идут по порядку в HTML, поэтому сильно перемешивать блоки относительно разметки не стоит.
Столбцы и единица fr
Задача: три колонки, первая — треть ширины, вторая — 100px, третья — остаток. Решение «в процентах» ломается. В контейнере шириной 600px:
.grid { grid-template-columns: 33.33% 100px 66.67%; }
Результат прогона: колонки 200 + 100 + 400 = 700px, третья вылезает за контейнер на 100px: проценты не учитывают соседние фиксированные треки.
Исправление — fr (fraction, доля свободного места):
.grid { grid-template-columns: 1fr 100px 2fr; }
Теперь 167 + 100 + 333 = 600px. Браузер сначала вычитает фиксированные треки и зазоры, а остаток делит по долям: (600 — 100) / 3 на одну долю. С gap: 20px на доли остается 460px, и колонки становятся 153, 100 и 307px.
Повторы сокращает repeat(): repeat(3, 1fr) — то же, что 1fr 1fr 1fr. Функцию можно смешивать с обычными значениями: grid-template-rows: 50px repeat(2, 2fr).
Ловушка: 1fr не всегда меньше контейнера
1fr по спецификации означает minmax(auto, 1fr): колонка не сжимается уже самого длинного неразрывного содержимого. Длинное слово или URL без пробелов и дефисов в колонке 1fr 1fr контейнера 600px дало в прогоне колонки 852 и 8px — сетка вылезла за контейнер.
.grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
.grid > * { overflow-wrap: anywhere; }
С minmax(0, 1fr) колонки снова по 300px, а overflow-wrap: anywhere переносит длинную строку внутри ячейки вместо вылезания текста за ее край.
Адаптивные карточки без медиазапросов
.cards {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 16px;
}
Браузер помещает столько колонок не уже 200px, сколько влезает, и растягивает их на остаток. В контейнере 1000px получилось 4 колонки по 238px, в контейнере 500px — 2 колонки по 242px.
auto-fill и auto-fit отличаются, только когда элементов меньше, чем помещается колонок. С двумя карточками в 1000px auto-fill сохраняет пустые треки (карточки по 238px слева), а auto-fit схлопывает их, и две карточки растягиваются по 492px.
Размещение по линиям
Элемент можно поставить на конкретные линии, остальные браузер разложит в свободные ячейки сам:
.grid { display: grid; grid-template-columns: repeat(4, 100px); grid-auto-rows: 40px; }
.a { grid-column: 1 / 3; } /* с 1-й по 3-ю линию: 2 колонки */
.b { grid-column: span 2; grid-row: 2; } /* 2 колонки во второй строке */
.c { grid-column: 1 / -1; } /* от первой до последней линии */
Прогон с порядком A, B, D, C: A занял колонки 1-2 первой строки, D без правил встал в третью колонку рядом, B — во вторую строку, C растянулся на все 400px в третьей. Записи grid-column: 1 / 3 и пара grid-column-start: 1; grid-column-end: 3 равнозначны, отрицательные номера считают линии с конца явной сетки.
Области и их правила
Карта grid-template-areas строится по трем правилам: в каждой строке одинаковое число ячеек, точка . — пустая ячейка, область с одним именем обязана быть прямоугольником. Нарушение не дает «кривую» область — браузер отбрасывает объявление целиком:
.bad { grid-template-areas: "x y" "y x"; }
В прогоне getComputedStyle() вернул для grid-template-areas значение none, а элемент с grid-area: y уехал в неявные треки за край сетки. Если разметка «развалилась», первым делом проверьте прямоугольность областей и число ячеек в строках.
Свойство grid-template объединяет строки, столбцы и области в одну запись: grid-template: auto 1fr / 200px 1fr — сначала строки, после слеша столбцы.
Отступы: gap
gap: 10px 30px задает сначала зазор между строками, потом между столбцами — прогон подтвердил row-gap=10px, column-gap=30px. Одно значение ставит оба. Старое имя grid-gap браузеры принимают как синоним, в новом коде пишут gap.
Выравнивание
| Свойство | Где задают | Что двигает |
|---|---|---|
justify-items / align-items |
Контейнер | Все элементы внутри своих ячеек, по горизонтали / вертикали |
justify-self / align-self |
Элемент | Один элемент внутри своей ячейки |
justify-content / align-content |
Контейнер | Всю сетку треков внутри контейнера |
*-content работает, только если треки в сумме меньше контейнера. Проверка: контейнер 600×200, треки 2 по 100px и 2 по 50px, justify-content: center; align-content: end; align-items: center. Первая ячейка началась с x = 200 и y = 100 от края контейнера, а элемент высотой 20px встал по центру строки в 50px. Значение по умолчанию у *-items — stretch: элемент растянут на всю ячейку. Сокращения place-items и place-content пишут оба значения сразу.
Grid или Flexbox
| Критерий | Grid | Flexbox |
|---|---|---|
| Оси | Две: строки и столбцы связаны | Одна главная ось; при flex-wrap строки выравниваются независимо |
| От чего идет раскладка | От сетки: треки задают, элементы в них ставят | От содержимого: размер элементов определяет раскладку |
| Типовые задачи | Макет страницы, галерея, карточки с выровненными колонками | Меню, панель кнопок, центрирование, строка из иконки и текста |
Правило выбора: если нужно, чтобы элементы совпадали и по строкам, и по столбцам — Grid. Если элементы идут потоком в одну линию — Flexbox. Их часто совмещают: сетка страницы на Grid, содержимое шапки на Flexbox.
Вложенная сетка и subgrid
Элемент сетки сам может стать контейнером (display: grid), но его сетка независима от родительской. Отсюда частая проблема: в соседних карточках заголовки разной высоты, и кнопки «Подробнее» стоят вразнобой. subgrid заставляет вложенную сетку взять треки родителя:
.cards { display: grid; grid-template-columns: repeat(3, 200px); gap: 16px; }
.card { display: grid; grid-row: span 3; grid-template-rows: subgrid; gap: 8px; }
Каждая карточка <article> с тремя детьми (<h3>, <p>, ссылка-кнопка) занимает три строки родителя и делит их с соседями. В прогоне кнопки всех трех карточек встали на одну высоту. В варианте без subgrid (у .card только display: grid; gap: 8px; align-content: start) кнопки разошлись примерно на 20px — точный сдвиг зависит от шрифта. Условие работы: элемент должен сам охватывать нужное число треков родителя (span 3), иначе подсетке нечего наследовать.
Поддержка: subgrid есть в актуальных Chrome, Edge, Firefox и Safari, в Chromium он появился позже всех, в версии 117 (2023 год).
Если не получилось
| Симптом | Причина | Что сделать |
|---|---|---|
| Свойства сетки не действуют на блок | Он не прямой потомок контейнера | Сделать родителя контейнером или использовать subgrid |
| Сетка шире контейнера | Проценты плюс фиксированные треки или длинное слово в 1fr |
Перейти на fr, minmax(0, 1fr) |
grid-template-areas игнорируется |
Область не прямоугольник или разное число ячеек | Выровнять карту, пустые ячейки — точкой |
justify-content ничего не делает |
Треки fr уже заняли всю ширину |
Задать треки фиксированной ширины или двигать элементы через *-items |
| Лишняя строка внизу | Элементов больше ячеек, созданы неявные треки | Добавить ряды или задать grid-auto-rows |
В DevTools Chrome и Firefox рядом с контейнером есть бейдж grid: он включает наложение с номерами линий и именами областей.
Выводы
- Grid раскладывает прямых потомков контейнера сразу по строкам и столбцам; для потока в одну линию удобнее Flexbox.
frделит место, оставшееся после фиксированных треков иgap; проценты с фиксированными колонками легко переполняют контейнер.repeat(auto-fill или auto-fit, minmax(...))дает адаптивную сетку без медиазапросов, аminmax(0, 1fr)защищает от распирания длинным содержимым.- Области в
grid-template-areasобязаны быть прямоугольными, иначе объявление отбрасывается целиком. subgridвыравнивает содержимое соседних карточек по общим трекам родителя и работает во всех актуальных браузерах.
Где применяется / связь с практикой
Освойте тему на практике
Grid — основной инструмент для каркаса страниц, каталогов, дашбордов и лендингов. Системно пройти HTML, CSS, адаптивность и сборку макета в живой проект можно на курсе HTML/CSS. Отдельные темы верстки удобно разобрать с преподавателями на бесплатных открытых уроках Otus.
FAQ
Можно ли верстать таблицы данных на Grid вместо <table>?
Для табличных данных лучше оставить <table>: у нее есть семантика строк и заголовков для скринридеров. Grid подходит для раскладки, а не для смысла данных.
Нужен ли префикс -ms- для Grid?
Нет: старый синтаксис -ms-grid был нужен только Internet Explorer, поддержка которого Microsoft прекращена в 2022 году.
Как сделать масонри-раскладку (кладку разной высоты) на Grid?
Штатного стабильного решения пока нет: спецификация masonry в CSS еще в работе, поэтому используют колонки CSS (columns) или JavaScript.



