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

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

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