CSS flexbox макет
CSS Flexbox - це модель верстки, яка розміщує елементи вздовж однієї осі (рядок або стовпець), автоматично розподіляючи простір, вирівнювання та розміри всередині контейнера.
Теорія
TL;DR
- Flexbox схожий на конвеєрну стрічку: елементи самі розставляються, вирівнюються і змінюють розмір без фіксованих позицій
- Головна різниця від float: flexbox дає передбачуване вирівнювання по двох осях, основній і поперечній
- Використовуй для одновимірних макетів (навбар, кнопки); для двовимірних (дашборди) бери CSS Grid
flex-directionза замовчуванням -row(зліва направо)justify-contentкерує основною віссю;align-itemsкерує поперечною
Швидкий приклад
.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 на батьківському елементі:
.container { /* display: flex відсутній */ }
.item { flex: 1; } /* Ігнорується - елементи досі стакуються вертикально */flex: 1 на нащадку не працює без flex-контейнера. Додай display: flex до .container.
align-items по неправильній осі при column:
.container {
display: flex;
flex-direction: column;
align-items: center; /* Центрує горизонтально, НЕ вертикально */
}При flex-direction: column властивість align-items керує горизонтальним вирівнюванням. Для вертикального центрування в колонці використовуй justify-content: center.
Немає flex-wrap при переповненні:
.container { display: flex; flex-wrap: nowrap; width: 200px; }
.item { width: 100px; } /* 5 елементів = переповнення */nowrap стоїть за замовчуванням. При великій кількості елементів вони стискаються або виходять за межі. Додай flex-wrap: wrap.
Очікування рівних ширин без flex: 1:
.container { display: flex; }
.item { /* за замовчуванням flex: 0 1 auto - розмір по контенту */ }Без flex: 1 елементи не ділять простір порівну. Вони мають розмір відповідно до свого вмісту. Постав flex: 1 на елементи, які мають рости рівномірно.
Конфлікт min-width і flex-grow:
.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.
Приклади
Навігаційна панель
Типовий навбар: лого ліворуч, посилання праворуч.
<nav class="navbar">
<h1>Logo</h1>
<ul>
<li>Home</li>
<li>About</li>
<li>Contact</li>
</ul>
</nav>.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.
Макет із фіксованим сайдбаром
Сторінка з фіксованою боковою панеллю і гнучкою основною зоною.
.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-патернів у продакшені.
Sticky footer
Футер завжди внизу, навіть на коротких сторінках.
body {
display: flex;
flex-direction: column; /* Хедер, основний контент, футер стакуються вертикально */
min-height: 100vh;
}
main {
flex: 1; /* Росте щоб заповнити залишок, відштовхуючи футер вниз */
}flex: 1 на main - це ключ. Він росте, щоб заповнити весь доступний вертикальний простір, тому футер залишається внизу незалежно від висоти контенту.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.