HTML & CSS

CSS Grid. Двовимірний макет. Частина 1

Глибоке занурення у CSS Grid Layout: display grid, одиниця fr, repeat(), minmax(), auto-fill, auto-fit, розміщення елементів через grid-column та grid-row, gap. Основи двовимірної сітки.

CSS Grid. Двовимірний макет

Коли одного виміру стає замало

Уявіть, що ви верстаєте типову сторінку сучасного застосунку: зліва — бічна панель навігації, зверху — шапка, в центрі — основний контент, знизу — підвал. Flexbox впорається з розміщенням елементів усередині кожного з цих блоків, але організувати весь цей каркас в двох вимірах одночасно — горизонтально та вертикально — він не призначений. Саме тут на сцену виходить CSS Grid Layout.

Grid (сітка) — це найпотужніша система компонування в CSS. Вона дозволяє розмістити елементи у двовимірній матриці рядків і колонок, явно контролюючи, де саме знаходиться кожен елемент. Якщо Flexbox — це компонування в одному напрямку (рядок або колонка), то Grid — це компонування в обох напрямках одночасно.

У попередній статті ми детально розглянули Flexbox. Ця стаття — логічне продовження: ми з'ясуємо, коли Grid краще, ніж Flexbox, і навчимося будувати справжні сторінкові макети.

Grid та Flexbox — не конкуренти, а союзники. Flexbox ідеальний для компонентів і одновимірних списків; Grid ідеальний для макетів сторінок і двовимірних сіток. Вони часто використовуються разом: Grid задає загальний каркас, а Flexbox вирівнює вміст усередині кожної з секцій.

Передумови та еволюція

До появи Grid Layout веб-розробники будували багатоколонкові макети за допомогою float, потім — через Flexbox з flex-wrap. Обидва підходи мали критичний недолік: вони були одновимірними. Потрібен рядок? Будь ласка. Потрібна колонка? Теж без проблем. Але контролювати одночасно і рядки, і колонки — це вже завдання для Grid.

Специфікацію CSS Grid розробляла команда Microsoft ще у 2011 році (під Internet Explorer 10 з префіксом -ms-grid). Стандартна версія без префіксів стала доступна в усіх сучасних браузерах у 2017 році — це була революція у веб-верстці.

Loading diagram...
timeline
    title Еволюція CSS-компонування
    1996 : float + table
         : Хаки з таблицями для колонок
    2009 : Flexbox (draft)
         : Одновимірне гнучке компонування
    2011 : Grid (MS, -ms-prefix)
         : Перша реалізація в IE10
    2017 : Grid (всі браузери)
         : Стандарт без префіксів
    2020 : Subgrid
         : Grid всередині Grid
    2023 : Masonry layout (draft)
         : Нерівні рядки в Grid

Базова концепція: контейнер і клітинки

Як і Flexbox, Grid ґрунтується на взаємодії контейнера (grid container) та елементів (grid items):

  • Grid-контейнер — елемент з display: grid. Він задає структуру сітки.
  • Grid-елементипрямі дочірні елементи контейнера. Вони автоматично розміщуються у клітинках сітки.
  • Grid-лінії (grid lines) — горизонтальні та вертикальні лінії, що утворюють сітку. Нумерація починається з 1.
  • Grid-доріжки (grid tracks) — рядки (rows) і колонки (columns) між сусідніми лініями.
  • Grid-клітинка (grid cell) — найменша одиниця сітки, перетин рядка і колонки.
  • Grid-область (grid area) — прямокутна зона з однієї або кількох клітинок.
Loading diagram...
graph TD
    A["Grid-контейнер<br/>(display: grid)"] --> B["Grid-елемент 1<br/>(клітинка 1,1)"]
    A --> C["Grid-елемент 2<br/>(клітинка 1,2)"]
    A --> D["Grid-елемент 3<br/>(клітинка 1,3)"]
    A --> E["Grid-елемент 4<br/>(клітинка 2,1)"]
    A --> F["Grid-елемент 5<br/>(клітинка 2,2)"]
    A --> G["Grid-елемент 6<br/>(клітинка 2,3)"]
    style A fill:#6366f1,color:#fff
    style B fill:#f59e0b,color:#fff
    style C fill:#f59e0b,color:#fff
    style D fill:#f59e0b,color:#fff
    style E fill:#10b981,color:#fff
    style F fill:#10b981,color:#fff
    style G fill:#10b981,color:#fff
.container {
    display: grid; /* Активує Grid Layout */
}

Цього вже достатньо, щоб зробити контейнер grid-контейнером. Але без визначення колонок і рядків усі елементи просто складатимуться в одну колонку — рівно як при звичайному блоковому потоці. Справжня сила grid починається з grid-template-columns.


grid-template-columns та grid-template-rows

Ці дві властивості — серце всього Grid Layout. Вони визначають розмір і кількість колонок та рядків відповідно.

Синтаксис

Значення — це список розмірів, розділених пробілами. Кожне значення описує одну доріжку:

.container {
    display: grid;
    grid-template-columns: 200px 400px 200px; /* 3 колонки */
    grid-template-rows: 80px 1fr 60px; /* 3 рядки */
}

Розберемо, що тут відбувається:

  • grid-template-columns: 200px 400px 200px — три колонки фіксованої ширини: 200px, 400px та 200px. Разом 800px. Все, що залишається після них, — порожній простір.
  • grid-template-rows: 80px 1fr 60px — три рядки. Перший і третій мають фіксовану висоту, а другий (1fr) займає весь простір, що залишився.
Preview
×
🔒localhost:3000

У прикладі ми вже використали grid-column: 1 / 3 — це розміщення елемента, яке ми детально розглянемо далі. Поки зверніть увагу на те, як Grid бере під контроль увесь простір.


Одиниця fr — частка вільного простору

Одиниця fr (fractional unit, частка) — це нова одиниця виміру, введена спеціально для CSS Grid. Вона означає "частку вільного простору в контейнері" і не є відсотком чи пікселем.

Як працює fr

Алгоритм розрахунку простий:

  1. Браузер відраховує фіксовані розміри (px, em, auto та ін.).
  2. Залишок вільного простору ділиться між усіма fr-доріжками пропорційно до їх коефіцієнтів.
.container {
    display: grid;
    grid-template-columns: 1fr 2fr 1fr;
    /* Вільний простір = 100% - gap */
    /* 1fr = 25% вільного | 2fr = 50% | 1fr = 25% */
}
Preview
×
🔒localhost:3000
fr vs %: відсоток береться від ширини всього контейнера, через що виникають проблеми з gap — сума відсотків перевищить 100%. Одиниця fr враховує gap автоматично, оскільки бере тільки вільний простір після відрахування проміжків. Завжди надавайте перевагу fr над % у Grid.

repeat() — стислий запис повторюваних доріжок

Написати 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr для дванадцятиколонної сітки — незручно та негарно. Функція repeat() вирішує цю проблему:

.container {
    /* Замість: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr */
    grid-template-columns: repeat(12, 1fr); /* Дванадцять рівних колонок */
}

Синтаксис repeat()

repeat(кількість, розмір-або-шаблон)

Перший аргумент — кількість повторень. Другий — шаблон (може містити кілька значень):

.container {
    /* Повторити шаблон "80px 1fr" тричі → тобто 6 колонок */
    grid-template-columns: repeat(3, 80px 1fr);
    /* Результат: 80px 1fr 80px 1fr 80px 1fr */
}

repeat() також може приймати спеціальні ключові слова auto-fill та auto-fit замість числа — про них поговоримо в наступному розділі.


minmax() — гнучкі межі розміру

Функція minmax(мінімум, максимум) дозволяє задати діапазон розміру для доріжки: вона буде не меншою за мінімум і не більшою за максимум.

.container {
    /* Колонки: мінімум 200px, максимум — рівна частка вільного простору */
    grid-template-columns: repeat(3, minmax(200px, 1fr));
}

Це надзвичайно корисно для адаптивних сіток: колонки ніколи не звужуються нижче 200px, але при великому екрані рівномірно заповнюють весь простір.

auto як значення minmax

Ключове слово auto у minmax() означає: мінімум — розмір контенту, максимум — весь доступний простір:

grid-template-columns: minmax(auto, 1fr); /* те саме, що просто 1fr */
grid-template-rows: minmax(100px, auto); /* мінімум 100px, далі росте за контентом */

auto-fill та auto-fit — справді адаптивні сітки

Це найпотужніша комбінація у CSS Grid — repeat() з auto-fill або auto-fit і minmax(). Вона дозволяє автоматично визначати кількість колонок залежно від доступного простору, без media queries.

auto-fill — заповни доріжками, навіть порожніми

.gallery {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: 1rem;
}

Браузер запитує: "Скільки колонок шириною щонайменше 200px вміститься в контейнер?" Якщо контейнер 800px — це 4 колонки. Якщо 1200px — 6 колонок. Колонки з'являються та зникають автоматично. При auto-fill, якщо елементів замало, порожні доріжки все одно зберігаються (займають місце).

auto-fit — зтисни порожні доріжки

.gallery {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 1rem;
}

Різниця від auto-fill: коли елементів менше, ніж максимально можлива кількість колонок, auto-fit зтискає порожні доріжки до 0 і розтягує наявні елементи на весь простір.

.fill-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: 1rem;
}
/* Якщо контейнер 600px і є лише 2 елементи:
   Утворяться 4 колонки (4 × 150px = 600px).
   Перші 2 заповнені, останні 2 — порожні, але займають місце.
   Елементи НЕ розтягуються на весь рядок. */
Preview
×
🔒localhost:3000
Щоб побачити різницю між auto-fill та auto-fit найяскравіше, змініть ширину браузера або додайте більше елементів. При достатніх елементах поведінка однакова — різниця проявляється тільки коли елементів менше, ніж знаходиться колонок.

gap — проміжки в Grid

Властивість gap (раніше grid-gap) задає проміжки між рядками та колонками. Вживається одне або два значення:

.container {
    gap: 1rem; /* Однаковий відступ між рядками і колонками */
    gap: 16px 24px; /* row-gap column-gap */
    row-gap: 16px; /* Тільки між рядками */
    column-gap: 24px; /* Тільки між колонками */
}
gap не додає відступи по краях контейнера — тільки між елементами. Для відступів від країв використовуйте padding на контейнері. Ця поведінка часто дивує новачків, які очікують "поля" навколо сітки.

Grid-лінії: нумерація та іменування

Розуміння Grid-ліній — ключ до розміщення елементів. Уявіть сітку 3×3: вона має 4 вертикальні лінії (1, 2, 3, 4) та 4 горизонтальні лінії (1, 2, 3, 4). Нумерація завжди починається з 1, не з 0.

Вертикальні лінії:  1   2   3   4
                    |   |   |   |
Рядок 1:           [col1][col2][col3]
                    |   |   |   |
Рядок 2:           [col1][col2][col3]
                    |   |   |   |

Негативні числа рахуються з кінця: -1 — остання лінія, -2 — передостання тощо.

Loading diagram...
graph LR
    subgraph grid["Сітка 3 × 2 (3 колонки, 2 рядки)"]
        L1["Лінія 1 (-4)"] --- C1["Колонка 1"] --- L2["Лінія 2 (-3)"]
        L2 --- C2["Колонка 2"] --- L3["Лінія 3 (-2)"]
        L3 --- C3["Колонка 3"] --- L4["Лінія 4 (-1)"]
    end

grid-column та grid-row — розміщення елементів

Ці властивості дозволяють елементу зайняти певну область сітки, вказавши початкову та кінцеву лінії:

.element {
    grid-column: початок / кінець; /* вертикальні лінії */
    grid-row: початок / кінець; /* горизонтальні лінії */
}

Вони є скороченнями для grid-column-start/grid-column-end та grid-row-start/grid-row-end:

/* Ці записи — еквівалентні */
.element {
    grid-column: 1 / 3;
}
/* Те саме: */
.element {
    grid-column-start: 1;
    grid-column-end: 3;
}

Ключове слово span — "займи N доріжок"

Замість вказування кінцевої лінії можна вказати, скільки доріжок має зайняти елемент через span:

.element {
    grid-column: 1 / span 2; /* Починаючи з лінії 1, займи 2 колонки */
    grid-row: span 3; /* Займи 3 рядки (від поточної позиції) */
}
Preview
×
🔒localhost:3000

Розберемо ключові властивості прикладу:

  • .headergrid-column: 1 / 4 — займає від лінії 1 до лінії 4, тобто всі 3 колонки (еквівалентно grid-column: 1 / span 3).
  • .sidebargrid-row: 2 / 4 — займає від рядка 2 до рядка 4, тобто 2 рядки поспіль, створюючи "бічну панель на весь контент".
  • .maingrid-column: 2 / 4 — займає 2 і 3 колонку, пропустивши першу (там сайдбар).
  • .footergrid-column: 1 / 4 — аналогічно шапці, тягнеться через увесь рядок.

Ця явна система розміщення — одна з найпотужніших особливостей Grid. Ви точно знаєте, де знаходиться кожен елемент, незалежно від порядку в HTML.


Від'ємні числа ліній

Від'ємна нумерація дуже корисна, коли ви хочете елемент, що завжди тягнеться до останньої лінії, навіть якщо ви не знаєте, скільки колонок у сітці:

.full-width {
    grid-column: 1 / -1; /* Від першої до останньої лінії — завжди всі колонки */
}

.last-two {
    grid-column: -3 / -1; /* Останні 2 колонки */
}

Це особливо зручно при динамічній сітці (auto-fill/auto-fit), де кількість колонок змінюється залежно від ширини екрана.


Автоматичне розміщення

Якщо ви не вказуєте grid-column і grid-row для елемента, Grid автоматично розміщує його в наступну вільну клітинку — зліва направо, зверху вниз. Це автоматичне розміщення (auto placement).

.container {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    /* Елементи самі розповзуться по 3 колонках */
}
Preview
×
🔒localhost:3000

Зверніть увагу: елемент 3 займає 2 колонки (span 2). Браузер автоматично переносить елемент 4 на новий рядок, тому що в поточному рядку немає місця для 3 і 4 разом.

За замовчуванням автоматичне розміщення працює за рядками (grid-auto-flow: row). Можна змінити на grid-auto-flow: column — тоді елементи розміщуватимуться спочатку по стовпцю зверху вниз, потім переходять до наступного стовпця. Існує також grid-auto-flow: dense — алгоритм намагається "ущільнити" елементи, заповнюючи пробіли дрібнішими елементами.

grid-auto-rows та grid-auto-columns — неявна сітка

Коли елементів більше, ніж задано рядків у grid-template-rows, Grid автоматично створює нові рядки. Їх розмір за замовчуванням — auto (розмір контенту). grid-auto-rows дозволяє задати розмір для цих автоматично створених рядків:

.container {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    grid-template-rows: 200px; /* Явно задано лише перший рядок */
    grid-auto-rows: 150px; /* Всі наступні (автоматичні) рядки — 150px */
}

Явна сітка (explicit grid) — та, яку ви задаєте через grid-template-*. Неявна сітка (implicit grid) — рядки/колонки, які Grid створює автоматично.

Preview
×
🔒localhost:3000

Перший рядок (елементи 1–3) — явний, 200px. Наступні рядки (елементи 4–7) — неявні, 100px. Це критично важливо для карткових сіток: ви задаєте колонки, а кількість рядків не знаєте наперед — grid-auto-rows зробить усі автоматичні рядки однаковими.


Практика: Адаптивна картково-сітка

Об'єднаємо все вивчене: repeat(auto-fit, minmax(...)), gap, grid-auto-rows і скорочення span — щоб створити справжню адаптивну сітку карток без єдиного media query:

Визначити контейнер із авто-колонками

.cards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: 1.5rem;
    padding: 1.5rem;
}

Колонки автоматично з'являтимуться/зникатимуть залежно від ширини контейнера. Мінімальна ширина картки — 280px.

Задати висоту рядків через grid-auto-rows

.cards {
    grid-auto-rows: auto; /* Рядки ростуть за контентом */
}
.card-featured {
    grid-column: 1 / -1; /* Завжди розтягнеться на всі колонки */
}
Preview
×
🔒localhost:3000

Властивість grid-template — скорочення

grid-template — це скорочення, яке об'єднує grid-template-rows, grid-template-columns та grid-template-areas в один рядок:

.container {
    /* grid-template: рядки / колонки */
    grid-template: 80px 1fr 60px / 200px 1fr 1fr;
}
/* Еквівалентно: */
.container {
    grid-template-rows: 80px 1fr 60px;
    grid-template-columns: 200px 1fr 1fr;
}

Хоча запис стислий, він може заплутати. Рекомендація: на ранньому етапі вивчення завжди пишіть властивості окремо для ясності.


Резюме частини 1

У цій частині ми заклали фундамент розуміння CSS Grid:

display: grid

Активує Grid Layout на контейнері. Усі прямі дочірні елементи стають grid-елементами.

grid-template-columns / rows

Визначають кількість та розміри доріжок. Підтримують px, %, fr, auto, minmax(), repeat().

Одиниця fr

Частка вільного простору. Враховує gap автоматично. Завжди краще за % в контексті Grid.

repeat() + auto-fit + minmax()

Магічна комбінація для адаптивних сіток без media queries.

grid-column / grid-row

Явне розміщення елементів по лініях сітки. Підтримує span для охоплення кількох доріжок.

grid-auto-rows

Розмір рядків неявної сітки — тих, що Grid створює автоматично при переповненні.

У наступній частині ми розглянемо:

  • grid-template-areas — іменовані області (named areas)
  • place-items, place-content, place-self — вирівнювання в Grid
  • Flexbox vs Grid: коли що обирати
  • Практика: класичний page layout та masonry-сітка
  • Завдання трьох рівнів складності

Завдання для самоперевірки


Продовження: CSS Grid. Частина 2 — Named Areas, вирівнювання, Flexbox vs Grid

Copyright © 2026