Skip to main content

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

Швидкий приклад

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 GridFlexbox
Виміри2D: рядки і стовпці1D: головна вісь + поперечна
РозміщенняЯвні лінії, іменовані зони, auto-flowПорядок у потоці з переносом
Охоплення (span)Нативний grid-column: 1 / 3Недоступно нативно
Іменовані зониТак, grid-template-areasНі
Найкраще дляМакети сторінок, дашборди, перекриттяНавбар, картки, групи кнопок

Основні властивості

Властивості контейнера задають структуру сітки. grid-template-columns і grid-template-rows визначають розміри треків. gap додає простір тільки між треками (не по зовнішніх краях). grid-template-areas візуально описує іменовані зони.

css
.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 саме на ньому.

css
/* Рухає всі елементи - напевно не те що потрібно */ .container { justify-items: center; } /* Рухає тільки цей */ .featured { justify-self: center; }

Очікування що gap додасть відступи по зовнішніх краях.

gap додає простір тільки між треками. Зовнішніх відступів за специфікацією немає. Для зовнішнього простору - padding на контейнері.

Голий 1fr на маленьких екранах.

fr бере тільки вільний простір. Якщо його немає - треки стискаються до мінімуму. Використовуй minmax(200px, 1fr).

css
/* Нестабільно на маленьких екранах */ 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 рівня.

Приклади

Адаптивний макет сторінки

css
.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.

Дашборд з панелями що охоплюють кілька рядків

css
.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.

Елементи що перекриваються

css
.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-елементах працює так само як на позиційованих елементах коли вони займають пересічні зони сітки.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.

Дочитали статтю?