Skip to main content

CSS flexbox макет

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

Теорія

TL;DR

  • Flexbox схожий на конвеєрну стрічку: елементи самі розставляються, вирівнюються і змінюють розмір без фіксованих позицій
  • Головна різниця від float: flexbox дає передбачуване вирівнювання по двох осях, основній і поперечній
  • Використовуй для одновимірних макетів (навбар, кнопки); для двовимірних (дашборди) бери CSS Grid
  • flex-direction за замовчуванням - row (зліва направо)
  • justify-content керує основною віссю; align-items керує поперечною

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

css
.container { display: flex; /* Перетворює нащадків на flex items */ justify-content: space-between; /* Розподіляє елементи по основній осі */ align-items: center; /* Центрує по поперечній осі */ height: 100px; }

Три елементи всередині .container розтягнуться горизонтально з рівними проміжками і вирівняються по центру вертикально. Без float, без підрахунку margin.

Порівняння з float-версткою

До flexbox вертикальне центрування було відомою болячкою. Float-макети переносилися непередбачувано, а inline-block вимагав хаків з пробілами. В продакшені я бачив, як float-макети ламаються через проблеми з переносом частіше, ніж від майже будь-чого іншого в CSS.

Flexbox замінює все це двома властивостями. Контейнер стає гнучкою одиницею. Елементи ростуть або стискаються, щоб заповнити доступний простір по основній осі. Не треба рахувати margin для рівних відступів: просто вказуєш контейнеру як розподілити вільний простір.

Дві осі

Кожен flex-контейнер має дві осі:

  • Основна вісь - визначається flex-direction. За замовчуванням row (зліва направо).
  • Поперечна вісь - перпендикулярна до основної.

Коли flex-direction: column, основна вісь стає вертикальною. Це міняє місцями значення властивостей: justify-content тепер вирівнює вертикально, а align-items - горизонтально. Тут часто плутаються.

Властивості контейнера

ВластивістьЩо робить
flex-directionНапрямок головної осі: row, row-reverse, column, column-reverse
flex-wrapПеренос елементів: nowrap (за замовчуванням), wrap, wrap-reverse
justify-contentРозподіл по основній осі: flex-start, center, space-between, space-around, space-evenly
align-itemsВирівнювання по поперечній осі: stretch, center, flex-start, flex-end, baseline
align-contentРозподіл кількох рядків (тільки при flex-wrap: wrap)
gapВідстань між елементами

Властивості елементів

ВластивістьЩо робить
flex-growНаскільки елемент росте відносно сусідів (за замовчуванням: 0)
flex-shrinkНаскільки стискається (за замовчуванням: 1)
flex-basisПочатковий розмір до росту або стиснення (за замовчуванням: auto)
flexСкорочення: flex-grow flex-shrink flex-basis
align-selfПеревизначає align-items для одного елемента
orderЗмінює візуальний порядок без зміни HTML

Скорочення flex: 1 розгортається в flex: 1 1 0%. Це означає "рости, стискайся, починай від нульової ширини." Саме так отримують колонки рівної ширини.

Коли використовувати

  • Простий рядок або стовпець (навбар, група кнопок) - flexbox
  • Контент, який має переноситися (картки, теги) - flexbox з flex-wrap: wrap
  • Двовимірний макет (дашборд, сітка сторінки) - CSS Grid
  • Заміна старих float-багів - flexbox їх прибирає

Як браузер це обробляє

Коли браузер бачить display: flex, він створює flex formatting context (контекст форматування). Розраховує вільний простір по основній осі через flex-фактори зі скорочення flex, запускає кожен елемент через розрахунок гіпотетичного розміру, потім розподіляє залишок згідно з justify-content. Blink у Chrome робить це за один прохід reflow. Тому flexbox швидший за float для задач вирівнювання.

Типові помилки

Забули display: flex на батьківському елементі:

css
.container { /* display: flex відсутній */ } .item { flex: 1; } /* Ігнорується - елементи досі стакуються вертикально */

flex: 1 на нащадку не працює без flex-контейнера. Додай display: flex до .container.

align-items по неправильній осі при column:

css
.container { display: flex; flex-direction: column; align-items: center; /* Центрує горизонтально, НЕ вертикально */ }

При flex-direction: column властивість align-items керує горизонтальним вирівнюванням. Для вертикального центрування в колонці використовуй justify-content: center.

Немає flex-wrap при переповненні:

css
.container { display: flex; flex-wrap: nowrap; width: 200px; } .item { width: 100px; } /* 5 елементів = переповнення */

nowrap стоїть за замовчуванням. При великій кількості елементів вони стискаються або виходять за межі. Додай flex-wrap: wrap.

Очікування рівних ширин без flex: 1:

css
.container { display: flex; } .item { /* за замовчуванням flex: 0 1 auto - розмір по контенту */ }

Без flex: 1 елементи не ділять простір порівну. Вони мають розмір відповідно до свого вмісту. Постав flex: 1 на елементи, які мають рости рівномірно.

Конфлікт min-width і flex-grow:

css
.container { display: flex; width: 300px; } .item1 { flex: 1; min-width: 100px; } .item2 { flex: 2; }

item1 отримає свій мінімальний 100px першим, item2 забере решту (200px). Без min-width item1 може стиснутися більше, ніж очікується.

Де зустрічається на практиці

  • React-компоненти навбара (Material-UI App Bar використовує flex всередині)
  • Bootstrap: utility-класи .d-flex
  • Tailwind: flex, justify-between, items-center для хедерів і карток
  • VS Code: бокова панель - flex для секцій, що змінюють розмір

Питання для співбесіди

Q: Яке значення flex-direction за замовчуванням і що змінює row-reverse?
A: За замовчуванням row (зліва направо). row-reverse перевертає напрямок праворуч наліво, змінюючи початок і кінець основної осі. DOM-порядок не змінюється, тільки візуальний.

Q: Яка різниця між justify-content: space-between і space-around?
A: space-between ставить рівні проміжки між елементами, але не біля країв. space-around дає кожному елементу по половині проміжку з кожного боку, тому крайні елементи мають вдвічі менший відступ від краю контейнера, ніж проміжки між середніми.

Q: Чим align-content відрізняється від align-items?
A: align-items вирівнює елементи в одному рядку по поперечній осі. align-content розподіляє кілька рядків, коли flex-wrap: wrap створює більше одного ряду. Без переносу align-content нічого не робить.

Q: flex: 0 0 200px і margin: auto - що відбудеться у вузькому контейнері?
A: Елемент залишиться 200px і не стиснеться (немає flex-shrink). margin: auto поглинає вільний простір по основній осі і центрує елемент коли місце є. Якщо контейнер вужчий за 200px - елемент виходить за межі, якщо не встановлено flex-wrap.

Приклади

Навігаційна панель

Типовий навбар: лого ліворуч, посилання праворуч.

html
<nav class="navbar"> <h1>Logo</h1> <ul> <li>Home</li> <li>About</li> <li>Contact</li> </ul> </nav>
css
.navbar { display: flex; justify-content: space-between; /* Лого ліворуч, меню праворуч */ align-items: center; /* Обидва вертикально по центру */ padding: 0 20px; background: #333; } .navbar ul { display: flex; /* Вкладений flex: пункти меню в рядок */ list-style: none; gap: 1rem; }

Вкладені flex-контейнери працюють нормально. ul сам стає flex-контейнером для своїх li.

Макет із фіксованим сайдбаром

Сторінка з фіксованою боковою панеллю і гнучкою основною зоною.

css
.layout { display: flex; min-height: 100vh; } .sidebar { flex: 0 0 250px; } /* Фіксовані 250px, не росте, не стискається */ .main { flex: 1; } /* Займає весь простір що залишився */ .aside { flex: 0 0 200px; } /* Фіксовані 200px праворуч */

0 0 250px означає "починай від 250px, не рухайся." flex: 1 означає "візьми що залишилось." Ця комбінація - один з найпоширеніших flex-патернів у продакшені.

Футер завжди внизу, навіть на коротких сторінках.

css
body { display: flex; flex-direction: column; /* Хедер, основний контент, футер стакуються вертикально */ min-height: 100vh; } main { flex: 1; /* Росте щоб заповнити залишок, відштовхуючи футер вниз */ }

flex: 1 на main - це ключ. Він росте, щоб заповнити весь доступний вертикальний простір, тому футер залишається внизу незалежно від висоти контенту.

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

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

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

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