Skip to main content

Порівняння flexbox та CSS grid

Flexbox будує макети вздовж однієї осі (рядок або стовпець); CSS Grid будує на двох осях одразу (рядки і стовпці разом).

Теорія

Коротко

  • Flexbox = один ряд сидінь в автобусі: елементи течуть вздовж однієї осі та розтягуються або стискаються
  • Grid = схема кварталу: ти визначаєш вулиці І проспекти, елементи розміщуються на перетинах
  • Головна різниця: Flexbox розподіляє простір вздовж однієї осі; Grid контролює обидві одночасно
  • Одновимірний макет (навбар, група кнопок, ряд карток)? Flexbox. Сторінка або дашборд? Grid
  • Вони добре поєднуються: Grid для каркасу сторінки, Flexbox всередині кожної клітинки

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

Однаковий візуальний результат, різний рівень контролю:

html
<!-- Flexbox: елементи течуть вздовж головної осі --> <div class="flex-row"> <div class="item">Nav</div> <div class="item">Logo</div> <div class="item">Login</div> </div> <!-- Grid: треки визначено заздалегідь --> <div class="grid-layout"> <header>Header</header> <aside>Sidebar</aside> <main>Content</main> </div>
css
/* Flexbox: одна вісь, простір розподіляється між елементами */ .flex-row { display: flex; justify-content: space-between; align-items: center; } /* Grid: дві осі, зони визначено явно */ .grid-layout { display: grid; grid-template-columns: 200px 1fr; grid-template-rows: 60px auto; grid-template-areas: "header header" "sidebar content"; }

Flexbox нічого не знає про рядки. Grid не займається потоком вмісту. Саме в цьому розриві й лежить рішення про вибір.

Ключова різниця

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

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

  • Навбар з логотипом і посиланнями: Flexbox (justify-content: space-between)
  • Ряд карток однакової висоти: Flexbox (align-items: stretch)
  • Макет з хедером, сайдбаром, контентом і футером: Grid
  • Дашборд з асиметричними панелями різного розміру: Grid (grid-template-areas)
  • Центрування одного елемента: підходять обидва (display: flex; place-items: center або display: grid; place-items: center)
  • Галерея де деякі елементи займають кілька колонок: Grid (grid-column: span 2)
  • Компонент всередині клітинки Grid, наприклад група кнопок у nav-зоні: Flexbox

Таблиця порівняння

АспектFlexboxCSS Grid
Виміри1D (рядок або стовпець)2D (рядки і стовпці)
Головна силаРозподіл простору вздовж однієї осіЯвне розміщення та перекриття елементів
Поведінка контейнераЕлементи займають доступний простірТреки визначено заздалегідь
Керування елементамиflex-grow, flex-shrink, flex-basis, ordergrid-area, grid-column, grid-row, place-self
Вирівнюванняjustify-content, align-items, align-selfjustify-items, align-items, place-items, place-content
Перекриття елементівСкладноНативна підтримка через спільну grid-зону
Підтримка браузерівIE10+, повна підтримка в сучаснихIE11 частково; subgrid з Chrome 117
Коли використовуватиНавбари, кнопки, ряди карток, центруванняМакети сторінок, дашборди, галереї

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

Коли браузер бачить display: flex, він створює flex formatting context. Спочатку обраховує гіпотетичний розмір кожного елемента через flex-basis, потім розподіляє залишковий простір відповідно до flex-grow. Перенос на новий рядок відбувається тільки при flex-wrap: wrap.

display: grid створює grid formatting context. Браузер будує карту треків з grid-template-columns і grid-template-rows, потім розміщує елементи або за явним grid-area, або через алгоритм автоматичного розміщення. Grid розраховує треки одноразово на початку; Flexbox перераховує при кожному reflow. Для довгих списків (1000+ елементів) Flexbox зазвичай швидший, бо кешування рядків простіше ніж розрахунок grid-треків.

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

Помилка 1: flex-direction: column для макету з сайдбаром і основним контентом

css
/* Неправильно: flex-direction column складає елементи зверху вниз */ .layout { display: flex; flex-direction: column; } /* Виправлення: Grid створює справжню структуру з колонками поруч */ .layout { display: grid; grid-template-areas: "sidebar main"; grid-template-columns: 240px 1fr; }

Це найпоширеніша помилка з макетами, яку я бачу на код-рев'ю. Розробники, які добре знають Flexbox, тягнуться до flex-direction: column коли потрібні колонки поруч, а він просто складає елементи вертикально.

Помилка 2: align-items: center на Grid для повного центрування

css
/* Неправильно: центрує тільки по поперечній осі кожного треку */ .grid { display: grid; align-items: center; } /* Виправлення: центрує по обох осях */ .grid { display: grid; place-items: center; }

align-items відповідає за block-вісь. justify-items - за inline-вісь. place-items - скорочення для обох, і саме воно потрібне для справжнього центрування.

Помилка 3: justify-content: space-between з елементами різного розміру

css
/* Виглядає нерівномірно коли ширина елементів різна */ .nav { display: flex; justify-content: space-between; } /* Виправлення: gap дає передбачуваний відступ */ .nav { display: flex; gap: 1rem; }

space-between розподіляє вільний простір між елементами. Якщо ширина елементів різна, проміжки візуально відрізняються. gap дає однакові відступи незалежно від розміру елементів і не виходить за зовнішні краї після перенесення рядка.

Помилка 4: Відсутність min-height: 0 у дочірніх елементах flex-колонки

css
/* Елемент відмовляється стискатись і виходить за межі батька */ .sidebar-item { display: flex; flex-direction: column; /* Відсутній: min-height: 0 */ } /* Виправлення */ .sidebar-item { display: flex; flex-direction: column; min-height: 0; /* Дозволяє стискатись нижче розміру контенту */ overflow: auto; }

Flex-елементи за замовчуванням мають min-height: auto, що не дозволяє стискатись нижче розміру контенту. В колонкових макетах це викликає переповнення. min-height: 0 знімає це обмеження.

Помилка 5: Subgrid без відповідних треків у батьківському елементі (Chrome 117+)

css
/* Батько визначає тільки два стовпці */ .grid-parent { display: grid; grid-template-columns: 1fr 2fr; } /* Subgrid автоматично використовує auto якщо кількість треків не збігається */ .grid-child { display: grid; grid-template-columns: subgrid; }

Subgrid успадковує треки батьківського елемента. Якщо батько не визначає потрібні треки, subgrid повертається до auto і вирівнювання ламається без жодних помилок. Спочатку визнач явні треки в батьківському елементі.

Де це зустрічається

  • React і Next.js: Flexbox для компонентів (кнопки та навбари в Chakra UI); Grid для структури додатку (дашборд Vercel)
  • Tailwind CSS: flex space-x-4 для inline-списків; grid-cols-12 для каркасу сторінок у темах Shopify
  • Bootstrap 5: .d-flex .justify-content-between побудований на Flexbox; складні форми з кількома колонками використовують Grid
  • Material UI: Flexbox у компонентах Card і List; Grid у таблицях даних

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

Q: Яка різниця між justify-content і justify-items?
A: justify-content розподіляє простір між треками або елементами на рівні контейнера. justify-items вирівнює кожен елемент всередині його власної grid-зони. У Flexbox є justify-content, але немає justify-items - ця властивість працює тільки в Grid.

Q: Чим відрізняється flex-basis від width?
A: flex-basis - це початковий розмір елемента до застосування flex-grow і flex-shrink. width - це розмір у блоковій моделі. Якщо задані обидва, у flex-контексті перемагає flex-basis. flex-basis: 0 змушує всі елементи починати з нуля і рівномірно зростати.

Q: Як працює grid-auto-flow: dense?
A: Коли spanning-елементи залишають порожні місця в сітці, dense наказує браузеру заповнювати їх меншими елементами з пізніших позицій у DOM. Це покращує щільність сітки, але змінює візуальний порядок відносно DOM-порядку, що може ускладнити навігацію клавіатурою.

Q: Чому gap краще за margins у flex або grid-контейнерах?
A: gap застосовується тільки між елементами, не на зовнішніх краях. Margins на дочірніх елементах накопичуються і можуть створювати подвійні відступи по краях або після перенесення рядка. gap коректно працює в обох контекстах.

Q: Що таке subgrid і коли він реально потрібен?
A: Subgrid дозволяє вкладеній сітці успадковувати розміри треків батьківської. Без нього картка всередині Grid-клітинки визначає власні внутрішні треки, які не збігатимуться з картками у сусідніх клітинках. З subgrid всі картки ділять однакові row-треки і їх контент вирівнюється по колонках. Доступно в Chrome 117+, Firefox 71+, Safari 16+. Для старших браузерів CSS custom properties на спільному батьківському елементі - практична альтернатива.

Приклади

Навбар на Flexbox (React, production-патерн)

jsx
function Navbar() { return ( <nav style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '1rem 2rem', borderBottom: '1px solid #eee' }}> <span style={{ fontWeight: 'bold' }}>Logo</span> <ul style={{ display: 'flex', listStyle: 'none', gap: '2rem', margin: 0 }}> <li>Home</li> <li>About</li> <li>Contact</li> </ul> <button>Login</button> </nav> ); }

Логотип зліва, навігація з рівними відступами, кнопка входу справа. Внутрішній ul теж flex-контейнер. Це і є патерн «Grid для каркасу, Flexbox всередині» на практиці.

Макет сторінки на CSS Grid

css
.app { display: grid; grid-template-columns: 240px 1fr; grid-template-rows: 60px 1fr 40px; grid-template-areas: "header header" "sidebar content" "footer footer"; min-height: 100vh; } header { grid-area: header; } aside { grid-area: sidebar; } main { grid-area: content; } footer { grid-area: footer; }

Іменовані зони роблять структуру читабельною з першого погляду. Зміни grid-template-columns на 1fr в media query - і весь макет перебудовується автоматично.

Галерея з перекриттям колонок

css
.gallery { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; } /* Виділений елемент займає дві перші колонки */ .gallery .featured { grid-column: span 2; }

Перкриття елементів - це те, де Grid не має аналога у Flexbox. Зробити один flex-елемент шириною двох колонок при збереженні спільної сітки неможливо. Grid підтримує це нативно.

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

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

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