The one-line rule
Flexbox is for one-dimensional layout — a row OR a column.Grid is for two-dimensional layout — rows AND columns simultaneously.
Flexbox: one direction at a time
Flexbox arranges items along a single axis — either horizontally (row) or vertically (column). The other axis is managed automatically. It excels at:
- Navigation bars — items in a row, space between them
- Centering a single item both horizontally and vertically
- Button groups and tag lists
- Distributing items with space-between or space-around
- Any layout where the number of items is dynamic (unknown at write-time)
.nav {
display: flex;
justify-content: space-between;
align-items: center;
}Flexbox is content-driven — the sizes and positions depend on the content. You start with items and arrange them.
Grid: two directions simultaneously
Grid defines a two-dimensional structure of rows and columns, then places items into that structure. It excels at:
- Page-level layouts — header, sidebar, main content, footer
- Card grids that need consistent column widths
- Complex layouts where items must align in both dimensions
- Any layout where the structure is defined independently of the content
.layout {
display: grid;
grid-template-columns: 240px 1fr;
grid-template-rows: auto 1fr auto;
min-height: 100vh;
}Grid is layout-first — you define the structure, then place content into it.
The decision table
| Scenario | Use |
|---|---|
| Navigation bar with items spaced evenly | Flexbox |
| Full page layout (sidebar + content) | Grid |
| Card gallery with consistent column widths | Grid |
| Center a button inside a div | Flexbox |
| Form label + input aligned in a row | Flexbox |
| Complex form with multiple columns and rows | Grid |
| Tag list that wraps to multiple lines | Flexbox (with flex-wrap) |
| Photo mosaic with items spanning multiple cells | Grid |
The case where you genuinely need both
A typical page layout uses Grid at the top level (page structure) and Flexbox inside components (navigation, card content, button groups). This is not a compromise — it is the intended usage:
/* Page layout: Grid */
.page {
display: grid;
grid-template-columns: 1fr 3fr;
}
/* Inside each card: Flexbox */
.card {
display: flex;
flex-direction: column;
justify-content: space-between;
}When either works (and which is simpler)
For a three-column equal-width layout, both work:
/* Grid approach */
.container { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; }
/* Flexbox approach */
.container { display: flex; gap: 1rem; }
.item { flex: 1; }Grid is slightly cleaner here. But for responsive layouts where columns should wrap automatically, Grid's auto-fill and minmax() are significantly more powerful:
/* Responsive grid — no media queries needed */
.cards {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 1rem;
}This creates as many columns as fit at 280px minimum, automatically wrapping to the next row. The equivalent in Flexbox requires more code.
Summary
- Flexbox: one axis, content-driven, dynamic item counts — nav, buttons, centering
- Grid: two axes, layout-driven, fixed structure — page layout, card grids, complex forms
- Use Grid at the macro level, Flexbox inside components
- For responsive grids without media queries, Grid's
auto-fill+minmax()is the best tool
Generate visual CSS grid layouts with the free CSS grid generator — adjust columns, rows, and gaps visually and copy the CSS.