CSS Grid and Flexbox are both powerful layout systems built into the browser — but they solve different problems. Flexbox is one-dimensional (row or column). Grid is two-dimensional (rows and columns simultaneously). This guide shows exactly when to use each, with side-by-side examples.
At a glance
| Flexbox | CSS Grid | |
|---|---|---|
| Dimensions | 1D — row or column | 2D — rows and columns |
| Direction | Main axis + cross axis | Explicit rows + columns |
| Item placement | Flow-based (auto) | Explicit or auto |
| Alignment | justify-content, align-items |
justify-items, align-items, place-items |
| Gap | gap |
gap / column-gap / row-gap |
| Browser support | 98%+ | 97%+ |
| Best for | Navigation bars, card rows, buttons, form controls | Page layouts, dashboards, image galleries, complex grids |
| Item sizing | flex-grow, flex-shrink, flex-basis |
fr, minmax(), auto-fill, auto-fit |
| Overlapping items | Not supported | Supported (z-index + grid placement) |
| Spec | CSS Flexible Box Module Level 1 | CSS Grid Layout Module Level 1 + 2 |
1. What Flexbox does
Flexbox aligns items along one axis at a time — either a row or a column. Items grow and shrink to fill available space.
.container {
display: flex;
flex-direction: row; /* or column */
justify-content: space-between; /* main axis */
align-items: center; /* cross axis */
gap: 1rem;
}
Flex item properties
.item {
flex-grow: 1; /* take remaining space */
flex-shrink: 0; /* don't shrink below flex-basis */
flex-basis: 200px; /* starting size */
/* shorthand */
flex: 1 0 200px;
}
Common Flexbox patterns
Centered element:
.parent {
display: flex;
justify-content: center;
align-items: center;
}
Equal-width columns:
.nav {
display: flex;
}
.nav-item {
flex: 1;
}
Push last item to end:
.toolbar {
display: flex;
align-items: center;
}
.toolbar .spacer {
flex: 1;
}
/* or: margin-left: auto on last item */
Wrap cards:
.card-list {
display: flex;
flex-wrap: wrap;
gap: 1rem;
}
.card {
flex: 1 1 300px; /* grow, shrink, min-width 300px */
}
2. What CSS Grid does
Grid creates a two-dimensional coordinate system. You define rows and columns explicitly, then place items anywhere in that system.
.container {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: auto;
gap: 1.5rem;
}
Grid item placement
/* Explicit placement */
.sidebar {
grid-column: 1 / 2;
grid-row: 1 / 3;
}
/* Span shorthand */
.feature-card {
grid-column: span 2;
}
/* Named areas */
.container {
grid-template-areas:
"header header header"
"sidebar main main"
"footer footer footer";
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.footer { grid-area: footer; }
Responsive grid without media queries
.gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 1rem;
}
auto-fill creates as many columns as fit. minmax(250px, 1fr) ensures each column is at least 250px wide and grows to fill space.
3. Flexbox vs Grid — real examples side by side
Navigation bar
Flexbox (perfect fit — 1D row):
.nav {
display: flex;
align-items: center;
gap: 2rem;
padding: 0 1rem;
}
.nav-logo { margin-right: auto; } /* pushes links to right */
Grid (overcomplicated for this):
/* Works but overkill */
.nav {
display: grid;
grid-template-columns: auto 1fr auto;
align-items: center;
}
→ Use Flexbox for nav bars.
Page layout
Grid (perfect fit — 2D layout):
.page {
display: grid;
grid-template-columns: 260px 1fr;
grid-template-rows: 60px 1fr 50px;
grid-template-areas:
"header header"
"sidebar content"
"footer footer";
min-height: 100vh;
}
Flexbox (requires nesting):
<!-- Needs multiple nested flex containers -->
<div class="flex-column">
<header>...</header>
<div class="flex-row">
<aside>...</aside>
<main>...</main>
</div>
<footer>...</footer>
</div>
→ Use Grid for page layouts.
Card grid
Grid (clean auto-placement):
.cards {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 1.5rem;
}
Flexbox (needs flex-wrap, less control):
.cards {
display: flex;
flex-wrap: wrap;
gap: 1.5rem;
}
.card {
flex: 1 1 280px;
max-width: calc(33.333% - 1rem); /* magic numbers */
}
→ Use Grid for card grids.
Button group / form controls
Flexbox (natural fit):
.button-group {
display: flex;
gap: 0.5rem;
align-items: center;
}
.form-row {
display: flex;
gap: 1rem;
align-items: flex-end;
}
→ Use Flexbox for inline controls.
4. Alignment comparison
Both Flexbox and Grid support justify-* and align-* properties, but they work differently.
| Property | Flexbox | Grid |
|---|---|---|
justify-content |
Distributes items on main axis | Distributes columns on inline axis |
align-content |
Distributes rows when wrapping | Distributes rows on block axis |
justify-items |
Not applicable | Aligns all items horizontally in cell |
align-items |
Aligns items on cross axis | Aligns all items vertically in cell |
justify-self |
Not applicable | Aligns single item horizontally |
align-self |
Aligns single item on cross axis | Aligns single item vertically |
place-items |
Not applicable | align-items + justify-items shorthand |
place-self |
Not applicable | align-self + justify-self shorthand |
place-content |
Shorthand for both | Shorthand for both |
Grid centering — simplest way:
.parent {
display: grid;
place-items: center; /* centers both axes */
}
Flexbox centering:
.parent {
display: flex;
justify-content: center;
align-items: center;
}
5. Sizing units
Flexbox: flex shorthand
/* flex: grow shrink basis */
.item { flex: 1 1 auto; } /* default */
.item { flex: 1; } /* flex-grow:1, flex-shrink:1, flex-basis:0 */
.item { flex: 0 0 200px; } /* fixed 200px, no grow/shrink */
.item { flex: 2; } /* takes twice as much space as flex:1 siblings */
Grid: fr units and minmax
/* fr = fraction of remaining space */
.grid {
grid-template-columns: 1fr 2fr 1fr; /* 25% 50% 25% */
}
/* minmax: at least 200px, grow to fill */
.grid {
grid-template-columns: repeat(3, minmax(200px, 1fr));
}
/* fixed + flexible */
.layout {
grid-template-columns: 260px 1fr; /* sidebar + content */
}
/* responsive without media queries */
.gallery {
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
}
auto-fill vs auto-fit:
auto-fill— creates empty columns even if no items fill themauto-fit— collapses empty columns, items expand to fill space- Use
auto-fitwhen you want fewer items to stretch across full width
6. Nesting Grid and Flexbox
They work great together. A common pattern: Grid for macro layout, Flexbox for micro layout inside grid cells.
/* Grid handles overall page structure */
.page {
display: grid;
grid-template-areas:
"header"
"main"
"footer";
grid-template-rows: auto 1fr auto;
}
/* Flexbox handles items inside header */
.header {
grid-area: header;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 2rem;
}
/* Flexbox handles card content layout */
.card {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.card-actions {
display: flex;
gap: 0.5rem;
margin-top: auto; /* push actions to bottom */
}
7. Subgrid (CSS Grid Level 2)
Subgrid lets nested elements align to the parent grid's tracks — eliminating the need for magic numbers to align columns across cards.
/* Parent grid */
.card-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
}
/* Each card spans 1 column but creates its own 3-row subgrid */
.card {
display: grid;
grid-row: span 3;
grid-template-rows: subgrid; /* aligns to parent row tracks */
}
/* Now all card titles, descriptions, buttons align across cards */
.card-title { /* row 1 */ }
.card-description { /* row 2 */ }
.card-actions { /* row 3 */ }
Browser support: Chrome 117+, Firefox 71+, Safari 16+. Use @supports for fallback.
8. Browser support and legacy fallbacks
| Feature | Chrome | Firefox | Safari | Edge |
|---|---|---|---|---|
| Flexbox | 29+ (2013) | 28+ (2014) | 9+ (2015) | 12+ |
| CSS Grid | 57+ (2017) | 52+ (2017) | 10.1+ (2017) | 16+ |
Grid gap |
66+ | 61+ | 12+ | 16+ |
subgrid |
117+ | 71+ | 16+ | 117+ |
auto-fit/auto-fill |
57+ | 52+ | 10.1+ | 16+ |
place-items |
59+ | 45+ | 11+ | 79+ |
All modern production browsers fully support both Flexbox and Grid. IE11 has partial Grid support (old spec) but IE11 is below 0.5% market share — ignore it in 2025.
9. Performance
Both layout systems are GPU-accelerated by the browser. Performance differences are negligible for typical UIs.
Practical tips:
- Avoid deeply nested flex/grid containers (increases layout calculations)
will-change: transformon animated items, not on containerscontain: layouton components that don't affect siblings- Prefer
transform+opacityfor animations — notwidth/height/margin
10. Decision guide
Need to center a single item?
→ display: grid; place-items: center;
1D layout (all in a row or all in a column)?
→ Flexbox
2D layout (rows AND columns matter)?
→ Grid
Navigation bar / toolbar?
→ Flexbox
Page-level layout (header/sidebar/main/footer)?
→ Grid
Card grid with equal columns?
→ Grid (auto-fill/auto-fit)
Card grid where column count varies by item?
→ Flexbox with flex-wrap
Items must overlap?
→ Grid (z-index + explicit placement)
Form controls / button groups?
→ Flexbox
Dashboard with panels?
→ Grid (named areas)
Complex responsive layout without media queries?
→ Grid (auto-fit + minmax)
Rule of thumb: If you're thinking about the container's overall structure, reach for Grid. If you're thinking about how items flow relative to each other, reach for Flexbox.
11. Quick reference: Flexbox properties
| Property | Values | Purpose |
|---|---|---|
display |
flex / inline-flex |
Enable Flexbox |
flex-direction |
row row-reverse column column-reverse |
Main axis direction |
flex-wrap |
nowrap wrap wrap-reverse |
Whether items wrap |
justify-content |
flex-start flex-end center space-between space-around space-evenly |
Main axis alignment |
align-items |
stretch flex-start flex-end center baseline |
Cross axis alignment |
align-content |
Same as justify-content |
Multi-line cross axis |
gap |
length | Space between items |
flex-grow |
number (default 0) | Grow factor |
flex-shrink |
number (default 1) | Shrink factor |
flex-basis |
length / auto |
Initial size |
align-self |
Same as align-items |
Override per item |
order |
integer | Visual reorder |
12. Quick reference: CSS Grid properties
| Property | Values | Purpose |
|---|---|---|
display |
grid / inline-grid |
Enable Grid |
grid-template-columns |
track sizes | Define columns |
grid-template-rows |
track sizes | Define rows |
grid-template-areas |
area names | Named layout |
grid-auto-columns |
track size | Implicit column size |
grid-auto-rows |
track size | Implicit row size |
grid-auto-flow |
row column dense |
Auto-placement direction |
gap / row-gap / column-gap |
length | Gutters |
grid-column |
start / end |
Item column placement |
grid-row |
start / end |
Item row placement |
grid-area |
name or row-start / col-start / row-end / col-end |
Item placement |
justify-items |
start end center stretch |
Inline alignment of all cells |
align-items |
start end center stretch |
Block alignment of all cells |
place-items |
align / justify |
Both axes shorthand |
justify-content |
start end center stretch space-around space-between space-evenly |
Distribute columns |
align-content |
Same | Distribute rows |
13. Common mistakes
| Mistake | Problem | Fix |
|---|---|---|
| Using Flexbox for a 2D page layout | Requires deeply nested containers | Switch to Grid for macro layout |
| Using Grid for a simple nav bar | Overcomplicated, fragile column sizing | Use Flexbox with margin-left: auto |
Forgetting min-width: 0 on flex items |
Text or images overflow container | Add min-width: 0 (or overflow: hidden) to flex children |
auto-fill when you want items to stretch |
Empty columns appear | Use auto-fit instead |
| Nesting flex inside flex too deeply | Brittle, hard to maintain | Extract inner components to Grid |
| Hardcoding column widths in Flexbox | Breaks on different viewports | Use flex: 1 1 minmax(...) or switch to Grid |
Using width: 50% inside a flex item |
Ignores flex model | Use flex-basis or flex: 0 0 50% |
Mixing align-items vs justify-content up |
Items appear in wrong place | Remember: justify = main axis, align = cross axis |
14. CSS Grid vs Flexbox vs other layout methods
| Layout method | Dimensions | Best for | Browser support |
|---|---|---|---|
| Flexbox | 1D | Component-level layout, nav, toolbars | 98%+ |
| CSS Grid | 2D | Page layout, dashboards, card grids | 97%+ |
| Float | 1D | Legacy only (avoid in new code) | 100% |
| CSS Multi-column | 1D | Magazine-style text columns | 95%+ |
| CSS Subgrid | 2D | Cross-card alignment | Chrome 117+, FF 71+, Safari 16+ |
| Table layout | 2D | Tabular data (use <table>) |
100% |
| Positioned layout | — | Overlays, tooltips, modals | 100% |
Frequently asked questions
Should I learn Flexbox or Grid first? Learn Flexbox first — it's simpler and solves most component-level problems. Then add Grid for page layouts and complex 2D arrangements. Most real projects use both.
Can I use Grid for everything? Yes, but you'll write more verbose CSS for simple 1D cases. Use the right tool for each job.
Does CSS Grid replace Flexbox? No. They complement each other. Grid excels at placing elements in two dimensions. Flexbox excels at distributing space along one axis. Most modern projects use both on the same page.
Which is faster — Grid or Flexbox? Performance is effectively identical for typical UI. Browser layout engines handle both efficiently. Don't choose based on performance.
How do I make a Flexbox layout responsive?
Use flex-wrap: wrap and flex: 1 1 <min-width> on items. For Grid, use repeat(auto-fit, minmax(250px, 1fr)) — no media queries needed.
Is CSS Grid supported in all browsers? Yes, in all modern browsers (Chrome, Firefox, Safari, Edge). IE11 has partial support with an older syntax, but IE11 is below 0.5% market share in 2025 — not worth worrying about.