Урок 4 · CSS
CSS Grid: раскладываем блоки по сетке
CSS Grid — модуль CSS для двумерной раскладки: контейнер описывает колонки и строки, а его прямые дети сами занимают ячейки. Grid включают через display: grid, колонки задают в grid-template-columns, промежутки — в gap. Им собирают каталоги карточек, галереи и макет страницы.
- Сетку описывают один раз — на родителе, дети встают в ячейки сами.
1fr— одна доля свободного места,repeat(3, 1fr)— три равные колонки.repeat(auto-fit, minmax(220px, 1fr))даёт адаптивную сетку без медиазапросов.- Линии нумеруются с 1,
grid-column: 1 / -1растягивает блок на всю ширину. - Grid — когда важны и строки, и колонки; для одного ряда проще Flexbox.
Зачем этот урок сейчас
После Flexbox кажется, что им можно собрать всё. Но как только карточки должны выстроиться в ровные ряды и колонки одновременно, flex начинает сопротивляться: последний ряд растягивается, высоты не совпадают, приходится считать проценты. Grid решает это одной строкой на родителе.
Первая сетка
.cards {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
}<div class="cards">
<article class="card">HTML</article>
<article class="card">CSS</article>
<article class="card">JavaScript</article>
<article class="card">Git</article>
</div>Получились три равные колонки с промежутком 20px. Четвёртая карточка сама ушла на вторую строку: строки создаются автоматически, их не нужно описывать заранее. Ширину карточкам задавать не надо — её задаёт колонка.
Термины Grid
| Термин | Что это |
|---|---|
| Контейнер | Элемент с display: grid |
| Элементы | Его прямые дети; внуки в сетку не попадают |
| Линии | Границы колонок и строк, нумеруются с 1 |
| Трек | Одна колонка или одна строка между двумя линиями |
| Ячейка | Пересечение одной колонки и одной строки |
| Область | Прямоугольник из нескольких ячеек, можно назвать по имени |
Единица fr и функция repeat
fr делит свободное место на доли. grid-template-columns: 2fr 1fr — левая колонка вдвое шире правой. Единицы можно смешивать: 240px 1fr — фиксированная боковая колонка и резиновая основная.
.layout { display: grid; grid-template-columns: 240px 1fr; gap: 32px; }
.gallery { display: grid; grid-template-columns: repeat(4, 1fr); }repeat(4, 1fr) — короткая запись для 1fr 1fr 1fr 1fr. Внутри repeat можно повторять и узор: repeat(2, 1fr 2fr) даст четыре колонки.
Адаптивная сетка без медиазапросов
.catalog {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 16px;
}Читается так: «сделай столько колонок, сколько поместится, каждая не уже 220px, а лишнее место раздели поровну». На широком экране будет четыре колонки, на телефоне — одна. Медиазапрос не нужен, пока меняется только число колонок; он понадобится, если на мобильном меняется сама структура макета.
auto-fit и auto-fill отличаются, когда карточек мало. auto-fill оставляет пустые колонки-заглушки, и две карточки займут лишь часть ряда. auto-fit схлопывает пустые колонки, и две карточки растянутся на всю ширину. Для каталога обычно нужен auto-fit.
Линии: как растянуть элемент
Элемент можно разместить по номерам линий или сказать, сколько треков он занимает.
.feature { grid-column: 1 / -1; } /* от первой линии до последней */
.wide { grid-column: span 2; } /* две колонки с текущего места */
.sidebar { grid-column: 3 / 4; grid-row: 1 / 3; }Конец не включается: grid-column: 2 / 4 занимает колонки 2 и 3. Отрицательные номера считаются с конца, поэтому -1 — всегда последняя линия, даже если число колонок меняется на разных экранах.
Именованные области grid-template-areas
Для макета страницы удобнее нарисовать сетку словами. Каждая строка в кавычках — ряд, каждое слово — ячейка, точка — пустая ячейка.
.page {
display: grid;
grid-template-columns: 220px 1fr;
grid-template-areas:
"header header"
"nav main"
"footer footer";
gap: 24px;
}
.page > header { grid-area: header; }
.page > nav { grid-area: nav; }
.page > main { grid-area: main; }
.page > footer { grid-area: footer; }
@media (max-width: 700px) {
.page {
grid-template-columns: 1fr;
grid-template-areas: "header" "main" "nav" "footer";
}
}На узком экране достаточно переписать карту областей — HTML не меняется. Области должны быть прямоугольными: буква «Г» из одного имени не сработает.
Выравнивание в Grid
| Свойство | Где пишут | Что выравнивает |
|---|---|---|
justify-items | контейнер | содержимое ячеек по горизонтали |
align-items | контейнер | содержимое ячеек по вертикали |
place-items | контейнер | обе оси сразу: place-items: center |
justify-content | контейнер | всю сетку, если колонки уже контейнера |
align-content | контейнер | все строки, если у контейнера есть лишняя высота |
justify-self, align-self | элемент | один элемент внутри своей ячейки |
По умолчанию элементы растягиваются на всю ячейку (stretch), поэтому карточки в одном ряду получаются одной высоты — то, чего так трудно добиться во flex.
Автоматические строки
Строки, которые не описаны в grid-template-rows, браузер создаёт сам — это неявная сетка. Их высоту задаёт grid-auto-rows: например, grid-auto-rows: minmax(160px, auto) — не ниже 160px, но растёт по содержимому. grid-auto-flow: dense разрешает браузеру заполнять дыры, которые оставили широкие элементы, но тогда визуальный порядок может разойтись с порядком в HTML.
Почему колонка 1fr вылезает
1fr на самом деле означает minmax(auto, 1fr): колонка не может стать уже своего содержимого. Длинный URL, широкая таблица или блок pre раздвигают колонку, и сетка вылезает за экран. Лечится явным минимумом:
.layout { grid-template-columns: 240px minmax(0, 1fr); }Grid или Flexbox
Двумерная раскладка: важны и строки, и колонки. Каталог, галерея, расписание, макет страницы.
Один ряд или одна колонка, элементы распределяют свободное место. Меню, шапка, кнопки внутри карточки.
Они не конкуренты: страница на grid, а шапка и кнопки внутри карточек — на flex.
Сетка в DevTools
В Chrome и Firefox рядом с grid-контейнером в панели Elements есть значок grid. Клик по нему рисует поверх страницы линии с номерами и имена областей. Так сразу видно, почему элемент встал не туда: обычно он занимает не те линии или не является прямым ребёнком контейнера.
Частые ошибки
- Пишут grid-свойства детям, хотя
display: gridнужен родителю. - Ждут, что внуки встанут в сетку: в неё попадают только прямые дети.
- Задают фиксированные колонки
300px 300px 300pxи ловят горизонтальную прокрутку на телефоне. - Путают
justify-items(содержимое ячеек) иjustify-content(вся сетка). - Считают линии с нуля:
grid-column: 1 / 3— это две колонки, а не три.
Доступность
Grid позволяет поставить блок куда угодно, но клавиатура и скринридер идут по порядку HTML. Если визуальный порядок сильно расходится с HTML (через order, номера линий или dense), человек с клавиатурой будет прыгать по странице. Сначала выстрой порядок в HTML по смыслу, сеткой только раскладывай.
Поддержка браузерами
CSS Grid поддерживается всеми актуальными браузерами с 2017 года, включая мобильные. gap для grid работает везде. subgrid — вложенная сетка, наследующая линии родителя, — появился позже и доступен в свежих версиях браузеров; его проверяй на Can I use.
Практика
Собери каталог: карточки не уже 220px, промежуток 16px, число колонок подстраивается под экран без медиазапроса. Первую карточку «Рекомендуем» растяни на всю ширину сетки. Затем добавь в одну карточку длинный URL без пробелов и убедись, что сетка не вылезает за экран.
Показать решение
.catalog {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 16px;
}
.catalog .featured {
grid-column: 1 / -1;
}
.catalog .card {
min-width: 0; /* разрешаем сжиматься */
overflow-wrap: anywhere; /* переносим длинный URL */
}Частые вопросы
Чем auto-fit отличается от auto-fill?
Когда карточек меньше, чем помещается колонок, auto-fill оставляет пустые колонки, а auto-fit их схлопывает, и карточки растягиваются на всю ширину. Для каталога обычно выбирают auto-fit.
Что значит 1fr?
Одна доля свободного места в контейнере. 1fr 2fr делит место в пропорции один к двум. Важно: 1fr не сжимается меньше содержимого, для этого пишут minmax(0, 1fr).
Почему элемент не встаёт в сетку?
Чаще всего он не прямой ребёнок grid-контейнера, а вложен в обёртку. Убери лишнюю обёртку, задай ей тоже display: grid или используй display: contents.
Нужны ли медиазапросы с Grid?
Для изменения числа колонок — нет, хватает repeat(auto-fit, minmax(…)). Медиазапрос нужен, когда на узком экране меняется сама структура: например, боковая колонка уходит под основной текст.
Как отцентровать блок через Grid?
Задай родителю display: grid; place-items: center;. Ребёнок встанет по центру по обеим осям.
Источники
Практикум по теме
- Карточки сами считают колонки — Одинаковые карточки не обязаны ждать отдельного правила на каждый размер экрана.