CSS grid layout
CSS Grid Layout - це двовимірна система CSS-макетів, яка ділить контейнер на рядки та стовпці і дозволяє точно розміщувати елементи по обох осях одночасно.
Теорія
TL;DR
- Уяви таблицю Excel: задаєш колонки і рядки, кидаєш елементи в конкретні клітинки
- Головна різниця з Flexbox: Grid керує рядками І стовпцями разом; Flexbox працює по одній осі
- Grid - для каркасу сторінки (header, sidebar, content, footer); Flexbox - всередині клітинок для вирівнювання компонентів
- Одиниця
frрозподіляє вільний простір після того, як фіксовані таauto-треки вже розраховані grid-template-areasдає тобі ASCII-карту макету прямо в CSS
Швидкий приклад
.container {
display: grid;
grid-template-columns: 1fr 2fr 1fr; /* вузька | широка | вузька */
grid-template-rows: auto 1fr auto; /* під контент | гнучкий | під контент */
gap: 1rem;
height: 100vh;
}Три стовпці (рівний, подвійний, рівний), три рядки (під вміст, гнучкий, під вміст). Елементи заповнюються зліва направо, зверху вниз за замовчуванням. Додай grid-template-areas - і отримаєш іменований макет, який читається з першого погляду.
Grid проти Flexbox
Grid створює явну сітку треків на контейнері і розміщує елементи в місцях їх перетину. Flexbox вишиковує елементи по одній осі та переносить їх при необхідності. Одне не замінює інше.
Grid - це скелет сторінки. Flexbox - м'язи всередині кожної клітинки.
Практичне правило: якщо потрібно керувати рядками і стовпцями разом (дашборд, журнальний макет, елементи що перекриваються) - Grid. Якщо просто рядок кнопок або список карток що переносяться - Flexbox простіший.
Коли використовувати
- Повний макет сторінки з header, sidebar, content, footer: Grid з
grid-template-areas - Дашборд з панелями що охоплюють кілька стовпців: Grid з
grid-column: 1 / -1 - Навігаційна панель з посиланнями по горизонталі: Flexbox
- Внутрішня структура картки (іконка + текст): Flexbox
- Адаптивна галерея з невідомою кількістю елементів:
repeat(auto-fill, minmax(250px, 1fr)) - Два елементи що перекриваються без
position: absolute: Grid, одна зона клітинок, різнийz-index
Таблиця порівняння
| Ознака | CSS Grid | Flexbox |
|---|---|---|
| Виміри | 2D: рядки і стовпці | 1D: головна вісь + поперечна |
| Розміщення | Явні лінії, іменовані зони, auto-flow | Порядок у потоці з переносом |
| Охоплення (span) | Нативний grid-column: 1 / 3 | Недоступно нативно |
| Іменовані зони | Так, grid-template-areas | Ні |
| Найкраще для | Макети сторінок, дашборди, перекриття | Навбар, картки, групи кнопок |
Основні властивості
Властивості контейнера задають структуру сітки. grid-template-columns і grid-template-rows визначають розміри треків. gap додає простір тільки між треками (не по зовнішніх краях). grid-template-areas візуально описує іменовані зони.
.layout {
display: grid;
grid-template-areas:
"header header header"
"sidebar content aside"
"footer footer footer";
grid-template-columns: 200px 1fr 200px;
grid-template-rows: auto 1fr auto;
gap: 1rem;
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.content { grid-area: content; }
.footer { grid-area: footer; }Без float. Без clearfix. Без position: absolute. Весь макет сторінки - шість рядків CSS.
Властивості елементів керують розміщенням і вирівнюванням. grid-column: 1 / 3 - від лінії 1 до лінії 3. grid-column: 1 / -1 - завжди повна ширина рядка, скільки б стовпців не було. justify-self і align-self вирівнюють один конкретний елемент у клітинці, не зачіпаючи сусідів.
repeat() та minmax()
repeat(3, 1fr) - три рівні стовпці. Корисніший шаблон: repeat(auto-fill, minmax(250px, 1fr)). Він створює стільки стовпців, скільки вміщається, кожен щонайменше 250px, і розподіляє залишок пропорційно. Заміни auto-fill на auto-fit - порожні хвостові треки зникнуть, елементи розтягнуться на весь рядок.
Різниця помітна коли елементів менше, ніж можливих стовпців. auto-fill залишає «примарні» треки. auto-fit їх прибирає.
Я не раз бачив як fr-стовпці падають майже до нуля на маленьких екранах. Рішення завжди одне: minmax(200px, 1fr) замість голого 1fr. Одиниця fr розподіляє тільки вільний простір - якщо його немає, треки стискаються до мінімального вмісту.
Як браузер обробляє Grid
display: grid запускає grid formatting context (контекст форматування сітки). Спочатку розраховуються фіксовані треки, потім auto, потім fr-одиниці отримують залишок. Явно розміщені елементи ідуть першими, решта auto-flow заповнює вільні клітинки. Зміна розміру вікна запускає алгоритм заново - тому складні комбінації minmax і fr на великих сітках можуть коштувати більше на resize, ніж простий Flexbox.
Типові помилки
Встановлення justify-items: center щоб відцентрувати один елемент.
justify-items центрує кожен елемент у кожній клітинці. Для одного конкретного елемента - justify-self: center саме на ньому.
/* Рухає всі елементи - напевно не те що потрібно */
.container { justify-items: center; }
/* Рухає тільки цей */
.featured { justify-self: center; }Очікування що gap додасть відступи по зовнішніх краях.
gap додає простір тільки між треками. Зовнішніх відступів за специфікацією немає. Для зовнішнього простору - padding на контейнері.
Голий 1fr на маленьких екранах.
fr бере тільки вільний простір. Якщо його немає - треки стискаються до мінімуму. Використовуй minmax(200px, 1fr).
/* Нестабільно на маленьких екранах */
grid-template-columns: repeat(3, 1fr);
/* Надійніше */
grid-template-columns: repeat(3, minmax(200px, 1fr));Вкладені сітки без висоти.
Дочірній display: grid не має висоти якщо батьківська клітинка не розтягує його. align-items: stretch є за замовчуванням, але може бути перевизначений. Перевіряй це першим коли вкладена сітка раптово схлопується.
Перекриття елементів у неправильному порядку.
Елементи перекриваються за порядком у DOM за замовчуванням. Додай явні значення z-index щоб контролювати що зверху. Grid-елементи приймають z-index так само як позиційовані елементи коли займають пересічні зони.
Де зустрічається в реальних проєктах
- Tailwind CSS:
grid grid-cols-12 gap-4для адаптивних дашбордів - Bootstrap 5:
row g-3з колонками для карткових сіток - Material-UI (MUI):
Grid container spacing={2}в React-застосунках - Chakra UI:
SimpleGrid columns={4}для авто-потокових галерей - GitHub: список файлів у репозиторії використовує grid для іконки, назви і колонки дій
Питання для поглиблення
Q: Яка різниця між grid-template і grid-template-columns?
A: grid-template - скорочення, що поєднує grid-template-columns, grid-template-rows і grid-template-areas в одному оголошенні. Окремі властивості зручніші коли потрібно змінити тільки один вимір без впливу на інші.
Q: Як працює імпліцитна сітка (implicit grid)?
A: Елементи розміщені за межами явної сітки автоматично створюють нові треки. grid-auto-rows і grid-auto-columns задають розміри цих треків. grid-auto-flow: dense заповнює прогалини перевпорядковуючи елементи візуально, DOM-порядок при цьому не змінюється.
Q: Що таке subgrid?
A: Subgrid (CSS Grid Level 2) дозволяє дочірній сітці вирівнювати свої треки за батьківською замість створення незалежних. Задається grid-template-rows: subgrid на дочірньому елементі. Зручно для вирівнювання контенту між кількома картками в одному ряду. Підтримка в сучасних браузерах є станом на кінець 2024 року.
Q: Коли перерахунок Grid дорожчий ніж Flexbox?
A: Складні комбінації minmax і fr перераховуються при кожній зміні розміру вікна. Велика сітка з багатьма auto-треками запускає важчий алгоритм ніж простий Flexbox-ряд. Профілюй у Chrome DevTools Performance panel перед оптимізацією.
Q: Чи можна зробити masonry layout на чистому CSS Grid?
A: grid-template-rows: masonry є в специфікації і був доступний за флагом у Firefox. Станом на 2024 рік жоден стабільний браузер не підтримує це. Поточні запасні варіанти - CSS column-count або JavaScript. Знання де специфікація і де реальна реалізація - ознака senior рівня.
Приклади
Адаптивний макет сторінки
.page {
display: grid;
grid-template-areas:
"header"
"content"
"footer";
grid-template-rows: auto 1fr auto;
min-height: 100vh;
gap: 1rem;
}
@media (min-width: 768px) {
.page {
grid-template-areas:
"header header"
"sidebar content"
"footer footer";
grid-template-columns: 250px 1fr;
}
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.content { grid-area: content; }
.footer { grid-area: footer; }На мобільному все складається вертикально. Від 768px sidebar з'являється зліва. Вся зміна - це дві властивості всередині media query.
Дашборд з панелями що охоплюють кілька рядків
.dashboard {
display: grid;
grid-template-columns: 250px 1fr 300px;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"sidebar header stats"
"sidebar content stats"
"sidebar footer footer";
gap: 2rem;
min-height: 100vh;
}
.sidebar { grid-area: sidebar; }
.header { grid-area: header; }
.content { grid-area: content; }
.stats { grid-area: stats; }
.footer { grid-area: footer; }Sidebar займає всі три рядки зліва. Панель stats справа охоплює два рядки. Footer перекриває останні два стовпці. Ця структура лежить в основі більшості адмін-панелей на Next.js і Remix.
Елементи що перекриваються
.canvas {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(3, 100px);
gap: 10px;
}
.card-red {
grid-column: 1 / 3; /* верхній лівий блок 2x2 */
grid-row: 1 / 3;
background: #e55;
z-index: 1;
}
.card-blue {
grid-column: 2 / 4; /* перекриває правий нижній кут червоного */
grid-row: 2 / 4;
background: #55e;
z-index: 2;
}Синій перекриває правий нижній кут червоного без обрізки. Без абсолютного позиціонування. z-index на grid-елементах працює так само як на позиційованих елементах коли вони займають пересічні зони сітки.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.