CSS Grid vs Flexbox — Stop Asking Which Is Better
r/css will argue Grid vs Flex forever. Shipping teams pick both before lunch. The useful question is not “which is better?” — it is “am I arranging in two dimensions or one?”
The one-sentence split
- Grid — control rows and columns as a single system (page regions, galleries, aligned form labels)
- Flexbox — distribute items along a single axis (nav links, tag chips, card actions)
Try page structures in a CSS grid playground when regions are the hard part; use Flex when children just need to space along a line.
Decision table
| Problem | Prefer | Why |
|---|---|---|
| Header / main / sidebar / footer | Grid | Named areas stay sane |
| Equal-height card mosaic | Grid | auto-fit + minmax |
| Navbar links with space-between | Flex | One axis |
| Center icon + label | Flex | align-items: center |
| Magazine-style asymmetric layout | Grid | Line-based placement |
| Unknown number of wrapping chips | Flex | flex-wrap |
| Align columns across rows (forms) | Grid | Shared tracks |
Page shell with Grid
.page {
min-height: 100dvh;
display: grid;
grid-template-columns: 240px 1fr;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"side header"
"side main"
"side footer";
}
@media (max-width: 800px) {
.page {
grid-template-columns: 1fr;
grid-template-areas: "header" "main" "footer";
}
.side { display: none; }
}
That structure fights you in pure Flex — you nest wrappers until it accidentally becomes a grid.
Component guts with Flex + nesting
.card-actions {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
justify-content: flex-end;
align-items: center;
}
.dashboard {
display: grid;
grid-template-columns: repeat(12, 1fr);
gap: 1rem;
}
.widget {
grid-column: span 4;
display: flex;
flex-direction: column;
gap: 0.75rem;
}
Grid places the widget; Flex owns the header chrome. Normal, not impure.
Myths and debugging
| Myth | Reality |
|---|---|
| “Grid replaces Flex” | Nest freely |
| “Flex for whole pages always” | Gets awkward for 2D |
“gap in flex is unreliable” | Widely supported now |
In DevTools, Grid overlay shows tracks; Flex overlay shows main/cross axis. Mysterious stretch is often Flex’s default align-items: stretch, not bad content height. Migrating a Flex shell to Grid? Move one region at a time so you can bisect regressions.
Litmus test: if one item grows taller, should neighbors in the other dimension realign as a system? Yes → Grid. No → Flex. Stop asking which is better; ask which axis you are designing.
Auto-fit galleries and form alignment
Card galleries are a Grid highlight:
.gallery {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
gap: 1rem;
}
Forms that must align labels and inputs across rows also want Grid (or a shared column template), not nested Flex rows that drift as copy lengths change. Conversely, a toolbar of actions that reflows onto two lines is Flex with flex-wrap — Grid is overkill when there is no second axis to align.
Subgrid note
When child grids must align to a parent’s columns, subgrid (where supported) beats brittle percentage hacks. Feature-detect or progressive-enhance; do not rewrite the whole site on subgrid alone. For most dashboards, nested Grid + Flex as described above is enough without waiting on subgrid.
When a teammate insists “we only use Flex here,” ask them to sketch the alignment lines on paper. If they draw both rows and columns, you have already won the Grid argument — the rest is syntax.
Container queries
As container queries spread, component-level Grid and Flex choices can respond to parent width instead of only viewport media queries — layout systems get more local and less global, which reduces breakpoint spaghetti.