HTML & CSS

CSS Flexbox: Фундамент гнучких макетів

Глибоке занурення в основи Flexbox: історія виникнення, поняття flex-контейнера та flex-елементів, осі (Main та Cross Axis), flex-direction, flex-wrap, flex-flow та використання gap.

CSS Flexbox: Фундамент гнучких макетів

Як ми верстали раніше: Ера хаків та болю

Уявіть собі просте завдання: у вас є контейнер, і ви хочете розмістити всередині нього три блоки в один ряд так, щоб вони займали весь доступний простір, а їх висота була однаковою, незалежно від кількості тексту в кожному. Сьогодні це звучить як елементарна задача для початківця. Але ще десять років тому це був справжній виклик, який вимагав глибоких знань специфічних CSS-трюків.

Історія веб-дизайну — це, багато в чому, історія спроб пристосувати інструменти, створені лише для стилізації тексту, до потреб побудови складних додатків.

До того як з'явився Flexbox (офіційно — CSS Flexible Box Layout Module), розробники проходили через кілька етапів еволюції макетів:

  1. Таблична верстка (<table>): На початку 2000-х сторінки збирали з HTML-таблиць. Це дозволяло легко робити колонки, але розмітка ставала неймовірно перевантаженою, несемантичною та важкою в підтримці. Таблиці не призначені для макетування сторінок, їхня мета — відображення табличних даних.
  2. Флоати (float): Властивість float була створена для єдиної мети: дозволити тексту обтікати картинку (як у газетних статтях). Але розробники швидко зрозуміли, що якщо дати блокам float: left, вони вишикуються в ряд! Це стало стандартом на багато років.
    • Проблема: Батьківський контейнер "не бачив" float-елементів і згортався (втрачав висоту). Доводилося використовувати трюк clearfix. Центрування по вертикалі залишалося нічним жахом, а забезпечити рівну висоту колонок без фіксованих розмірів було практично неможливо.
  3. Інлайн-блоки (inline-block): Давав можливість блокам вишиковуватися в ряд, зберігаючи при цьому здатність приймати розміри як блокові елементи.
    • Проблема: За замовчуванням між inline-block елементами браузер рендерив пробіли (оскільки вони розглядалися як текст). Щоб їх позбутися, використовували хаки на кшталт font-size: 0; на батьківському контейнері або зліплювали HTML-теги </div><div> без переносів рядків.

Давайте подивимось наживо, як це виглядало раніше.

Контекст: Ми хочемо зробити дві колонки однакової ширини:

/* Батьківський контейнер */
.container {
    width: 100%;
}
/* Очищення потоку, щоб батько мав висоту */
.container::after {
    content: "";
    display: table;
    clear: both;
}
/* Дочірні елементи */
.column {
    float: left; /* хак для колонок */
    width: 50%;
}

Текст пояснення: Зверніть увагу на .container::after. Це знаменитий clearfix. Без нього елемент .container мав би нульову висоту, оскільки float-елементи "випадають" з нормального потоку документа, і батько перестає їх містити. Це типовий приклад "корости", коли для простої задачі ми пишемо зовсім нелогічний з точки зору здорового глузду код.

Народження Flexbox

Індустрія потребувала інструменту, який би розумів концепцію розподілу простору та вирівнювання елементів. Таким інструментом став Flexbox. Flexbox (Flexible Box Layout) — це модель макетування, розроблена спеціально для створення гнучких, адаптивних користувацьких інтерфейсів в одновимірному просторі (тобто або в рядок, або в стовпчик).

Його головні суперсили:

  1. Розподіл простору: Flexbox вміє брати вільний простір контейнера і самостійно розподіляти його між елементами.
  2. Вирівнювання: Вертикальне та горизонтальне центрування тепер робиться двома рядками коду.
  3. Гнучкість: Елементи можуть стискатися або розширюватися залежно від доступного місця без фіксованих медіа-запитів.
  4. Порядок: Ми можемо візуально змінювати порядок елементів, не змінюючи HTML-код (властивість order).

Фундаментальні Концепції: Контейнер та Елементи

Архітектура Flexbox базується на двох ролях: Flex-контейнер (Flex Container) та Flex-елементи (Flex Items). Усе залежить від відношення "батько-дитина".

1. Flex-контейнер (Flex Container)

Контейнер — це елемент, для якого задана властивість display: flex (або display: inline-flex). Як тільки ви застосовуєте це правило, звичайний HTML-елемент набуває "магічних" властивостей. Він створює новий контекст форматування (Flex Formatting Context) для своїх прямих нащадків.

Важливо: Flexbox впливає лише на прямих дочірніх елементів. Він не впливає на "онуків" (елементи, які вкладені глибше) чи на вкладений текст (текст обертається в анонімні flex-елементи).

2. Flex-елементи (Flex Items)

Всі прямі дочірні елементи flex-контейнера автоматично стають flex-елементами. Їхня поведінка кардинально змінюється в порівнянні зі звичайними блоковими (block) елементами:

  • Відступи (margin) flex-елементів ніколи не згортаються (margin collapsing не працює у flexbox).
  • Властивості float, clear та vertical-align на flex-елементах ігноруються і не мають жодного ефекту.
Loading diagram...
graph TD
    A["&lt;div class='container'&gt;\ndisplay: flex;\n(Flex-контейнер)"] --> B["&lt;div class='item'&gt;\n(Flex-елемент 1)"]
    A --> C["&lt;div class='item'&gt;\n(Flex-елемент 2)"]
    A --> D["&lt;div class='item'&gt;\n(Flex-елемент 3)"]
    
    C --> E["&lt;p&gt;Текст&lt;/p&gt;\n(Звичайний блоковий елемент,\nНЕ flex-елемент)"]
    
    style A fill:#3b82f6,color:#fff,stroke:#1d4ed8
    style B fill:#f59e0b,color:#fff,stroke:#b45309
    style C fill:#f59e0b,color:#fff,stroke:#b45309
    style D fill:#f59e0b,color:#fff,stroke:#b45309
    style E fill:#64748b,color:#fff,stroke:#475569

Дві Осі Flexbox: Main Axis та Cross Axis

Ще одна фундаментальна частина парадигми Flexbox — це система координат на основі осей, а не звичних нам X та Y. Це найтонший момент, який потрібно глибоко усвідомити. У Flexbox все базується не на горизонталі/вертикалі, а на Головній осі (Main Axis) та Поперечній осі (Cross Axis).

Loading diagram...
graph LR
    subgraph ROW["Головна вісь горизонтальна (flex-direction: row)"]
        direction LR
        A["Main Axis (Головна) →"] -.-> B["Cross Axis (Поперечна) ↓"]
    end
    subgraph COL["Головна вісь вертикальна (flex-direction: column)"]
        direction TB
        C["Main Axis (Головна) ↓"] -.-> D["Cross Axis (Поперечна) →"]
    end
    style A fill:#3b82f6,color:#fff,stroke:#1d4ed8
    style B fill:#f59e0b,color:#fff,stroke:#b45309
    style C fill:#3b82f6,color:#fff,stroke:#1d4ed8
    style D fill:#f59e0b,color:#fff,stroke:#b45309

Чому це важливо? Властивості Flexbox майже ніколи не кажуть "вирівняти по вертикалі". Вони кажуть: "вирівняти по головній осі" (напр., justify-content) або "вирівняти по поперечній осі" (напр., align-items). Якщо головна вісь горизонтальна, то justify-content виставляє елементи зліва-направо. Але якщо ви зміните напрямок на вертикальний, justify-content почне вирівнювати елементи зверху-вниз!

Main Axis (Головна вісь)
concept
Вісь, вздовж якої розташовуються flex-елементи. За замовчуванням вона йде горизонтально зліва направо (у мовах з читанням зліва направо, LTR). Розміри елементів по цьому напрямку визначаються їхнім Main Size (зазвичай це width).
Cross Axis (Поперечна вісь)
concept
Вісь, перпендикулярна до головної осі. За замовчуванням вона йде вертикально зверху вниз. Розміри елементів по цьому напрямку визначаються їхнім Cross Size (зазвичай це height).

Архітектура та Механіка

Тепер перейдемо до практичної сторони. Як усе це втілити в коді? Почнемо зі створення самого контейнера та керування напрямком потоку.

Створення контейнера: display: flex

Щоб запустити механіку Flexbox, ми використовуємо властивість display.

.flex-container {
    display: flex; /* Або inline-flex */
}

Що відбувається "під капотом", коли ми це пишемо?

  1. Сам блок .flex-container продовжує вести себе як звичайний "блоковий" елемент зовнішньо — займає 100% ширини свого батька, скидає інші елементи на новий рядок. (Якщо використати display: inline-flex, він вестиме себе як inline-block, тобто підлаштує свою ширину під контент).
  2. Але всередині нього змінюється правила гри. Усі прямі дочірні елементи вишиковуються вздовж Головної осі (за замовчуванням — у рядок зліва направо).
  3. Елементи розтягуються, щоб заповнити всю висоту контейнера вздовж Поперечної осі (це поведінка align-items: stretch, що діє за замовчуванням).
  4. Елементи не переносяться на новий рядок, навіть якщо їм не вистачає місця; вони намагатимуться стиснутися (властивість flex-shrink за замовчуванням).

Подивіться на живий приклад. Ми візьмемо 3 звичайні <div>, які зазвичай були б складені один під одним, і перетворимо їхнього батька на flex-контейнер.

Preview
×
🔒localhost:3000

Аналіз коду вище:

  • В першому випадку (parent-normal), як і очікувалось для блокових елементів, кожен div займає 100% ширини і росте вниз.
  • У другому випадку (parent-flex), просто додавши display: flex, ми отримали зовсім іншу картину. Блоки вишикувались у горизонтальну лінію. Ширина кожного блоку тепер визначається його контентом (зверніть увагу, що Блок 2 ширший). А найголовніше — Блок 1 і Блок 3 автоматично розтягнулись по висоті, щоб дорівнювати найвищому елементу (Блоку 2). Це стандартна поведінка, яка робить дизайн карток неймовірно простим!

Напрямок Головної Осі: flex-direction

Властивість flex-direction застосовується до flex-контейнера і встановлює, куди саме буде направлена Головна вісь (Main Axis). Відповідно, це визначає напрямок розміщення елементів.

Думка про цю властивість як про рубильник, який повертає весь простір контейнера.

Доступно 4 значення:

  1. row (за замовчуванням): Елементи розташовуються лінійно зліва направо (у LTR мовах).
  2. row-reverse: Елементи розташовуються справа наліво.
  3. column: Елементи вишиковуються зверху вниз у стовпчик.
  4. column-reverse: Елементи розташовуються знизу вгору.

Давайте подивимось, як кожне значення впливає на макет.

Preview
×
🔒localhost:3000

Аналіз роботи flex-direction:

Що важливо відзначити:

  • Коли ви використовуєте row-reverse чи column-reverse, браузер не змінює HTML у дереві DOM. Він лише каже: "почни малювати елементи з протилежного кінця контейнера і рухайся у зворотний бік".
  • Зверніть увагу на порядок цифр "1", "2", "3" у демо вище. У випадку row-reverse елемент "1" стає найправішим.
  • Коли ви перемикаєтесь на column, контейнер тепер керується вертикально. Головна вісь пішла зверху вниз! Це означає, що якби ми застосували justify-content (вирівнювання по головній осі), воно б зараз центрувало елементи по вертикалі, а не по горизонталі.
Обережніше з доступністю (Accessibility):*-reverse властивості змінюють візуальний порядок, але скрін-рідери (програми екранного доступу для людей з порушеннями зору) та навігація клавіатурою (натискання клавіші ) продовжують слідувати порядку в HTML документі. Якщо ваша логіка вимагає певного порядку, змінюйте структуру HTML, а не використовуйте CSS-трюки для кардинальної реорганізації контенту. row-reverse гарно підходить для UI-перемикачів (напр., зміна аватарки з лівого на правий бік в чаті), але не для глобальної структури сторінки.

Перенос Елементів: flex-wrap

Одне з найважливіших налаштувань за замовчуванням у Flexbox: всі елементи намагаються втиснутись в один ряд. Це означає, що якщо загальна сума їх ширини перевищує ширину контейнера, вони почнуть стискатися (включається flex-shrink). Але що робити, якщо ми не хочемо, щоб вони стискались, а натомість переносились на новий ряд, як слова в абзаці тексту?

Для цього є властивість flex-wrap, яка застосовується до flex-контейнера.

Доступно 3 значення:

  1. nowrap (за замовчуванням): Всі елементи вміщуються в одну лінію.
  2. wrap: Елементи переносяться на нові лінії сверху вниз, якщо не вистачає місця.
  3. wrap-reverse: Елементи переносяться на нові лінії знизу вгору.

Давайте подивимось наживо.

Preview
×
🔒localhost:3000

Що відбувається в анатомії цього коду:

  1. Ми попросили браузер, щоб кожен елемент мав розмір близько 150px (за допомогою контенту або flex-basis).
  2. Загальна ширина 5 елементів становить близько 750px + проміжки.
  3. Але наш контейнер має обмеження: max-width: 450px.
  4. В режимі nowrap (за замовчуванням): Елементам байдуже на їхні 150px. Flexbox бачить, що місця обмаль, і стискає всі 5 блоків, щоб вони втіснилися в наявні 450px. Деякі написи можуть навіть переноситися всередині елементів.
  5. При перемиканні на wrap: Flexbox малює перший елемент (150px), другий (150px), а коли черга доходить до третього, він розуміє, що разом вони займуть 450px + gap, що більше об'єму контейнера. Тому третій елемент акуратно переноситься на новий ряд, утворюючи багаторядковий макет.

Ця властивість життєво необхідна для створення адаптивних сіток (responsive grids) або галерей, де ви хочете, наприклад, мати 4 колонки на комп'ютері, 2 на планшеті та 1 на мобільному пристрої, дозволяючи елементам вільно "спадати" вниз у міру звуження екрану.


Шорткат: flex-flow

Оскільки flex-direction та flex-wrap настільки часто використовуються разом і обидві визначають основу макету (напрямок + багаторядковість), CSS дозволяє об'єднати їх в одну коротку властивість flex-flow.

Синтаксис:

.container {
    flex-flow: <flex-direction> <flex-wrap>;
}

Приклади використання:

/* Рядок, стискаємо якщо не влазить */
.container { flex-flow: row nowrap; } 

/* Рядок, переносимо на нові ряди */
.container { flex-flow: row wrap; } 

/* Стовпчик з переносом (рідкість, але можливо, якщо контейнер обмежений по висоті) */
.container { flex-flow: column wrap; }

Застосовувати цей шорткат чи ні — справа особистих вподобань. Багато розробників віддають перевагу роздільним записам для більшої прозорості та зручності пошуку, проте в сучасному коді flex-flow зустрічається регулярно.


Ідеальні Проміжки: Властивість gap

Раніше, створення рівномірних відступів між десятками елементів у галереї було ще одним головним болем. Ми мали додавати до карток margin-right: 20px, потім усвідомлювати, що крайня права картка відштовхує контейнер, доводити виняток для :last-child, або додавати на контейнер від'ємний margin: -20px.

У сучасних версіях CSS для Flexbox додали властивість gap (яка раніше прийшла з Grid Layout). Властивість gap задається на Flex-контейнері і забезпечує проміжки лише між елементами, не створюючи зайвих відступів по краях, ніби вставляючи повітря між компонентами.

gap: 20px

Встановлює універсальний простір 20px як між рядками (по вертикалі), так і між колонками (по горизонталі).

row-gap: 15px

Задає простір лише між рядами. Діє переважно тоді, коли ввімкнено flex-wrap: wrap.

column-gap: 30px

Задає просторів лише між стовпчиками елементів у межах одного ряду.

Синтаксис шорткату, якщо ви хочете задати різні проміжки в одному рядку:

/* gap: <row-gap> <column-gap> */
.container {
    gap: 10px 30px; 
}
Preview
×
🔒localhost:3000

Як бачимо в анатомії нашого коду для демо, контейнер має gap: 1rem 3rem. Коли 4-й і 5-й елемент не влізли і перенеслися на новий рядок, Flexbox автоматично вставив між верхнім рядом і нижнім 1rem простору (це наш row-gap). А між сусідніми картками знаходиться відстань 3rem (це наш column-gap). Це робить код неймовірно чистим, безпечним та легко масштабованим. Жодного зайвого margin.

Best Practice: Забудьте про margin для створення простору між компонентами у флекс-сітках. Використовуйте gap всюди, де мова йде про відступи між дочірніми елементами. Залишайте margin лише для того, щоб відштовхнути весь контейнер від інших блоків на сторінці.

Резюме та Практика

Отже, ми ознайомились із фундаментом Flexbox:

  1. display: flex — це портал у новий вимір одновимірного макетування. Він застосовується до батька (контейнера).
  2. Макет будується навколо двох осей: Головної (Main Axis) та Поперечної (Cross Axis).
  3. Змінюючи flex-direction, ми міняємо напрямок Головної осі (вліво, вправо, вверх, вниз).
  4. flex-wrap дозволяє елементам спадати на нові лінії замість того, щоб нескінченно стискатися в одному ряду.
  5. Для створення ідеальних, надійних відступів між елементами без зайвих умов ми завжди використовуємо властивість gap.

Цього фундаменту достатньо для того, щоб задати загальний напрямок вашому інтерфейсу. Але для того, щоб справді контролювати, де саме елементи знаходяться на своїх осях, треба навчитися вирівнюванню.

Спробуйте закріпити сьогоднішній матеріал.

Практичні Навички рівня "Основи"

Наступним кроком ми розглянемо, як керувати розташуванням елементів уздовж наших двох осей. Готові переміщувати пікселі? Переходьте до статті про Вирівнювання у Flexbox.

Copyright © 2026