You need three cards in a row. Flexbox does that in four lines. Then the client wants a fourth card, and now you’re fighting flex-wrap, and the last row has one lonely card stretched across the full width because Flexbox has no idea it’s supposed to line up under the row above it.
This is usually the exact moment someone reaches for Grid. And it’s usually the moment they realize nobody ever explained when to reach for which — just a wall of syntax for both. Here’s the version that actually answers that.
Flexbox lays things out in one direction at a time — a row, or a column. Grid lays things out in two directions at once. If you’re aligning items along a single line, use Flexbox. If you’re building a layout where rows and columns need to line up with each other, use Grid. Most real pages use both, at different levels.
The one-sentence mental model
Flexbox is one-dimensional. Grid is two-dimensional.
That’s it — everything else follows from that. Flexbox items flow along a single axis and wrap onto a new line when they run out of room, but each line doesn’t know or care what the line before it looked like. Grid defines the rows and columns up front, so every item is placed into a specific track, and everything lines up — horizontally and vertically — on purpose.
That’s exactly what broke in the four-card example above: row two had no relationship to row one, because Flexbox was never tracking rows in the first place.
Grid vs Flexbox at a glance
| Flexbox | Grid | |
|---|---|---|
| Dimensions | One axis at a time (row or column) | Two axes at once (rows and columns) |
| Best for | Aligning items inside a component | Structuring the page or section layout |
| Driven by | Content — items size themselves | Layout — you define the tracks, content fills them |
| Wrapping | New rows have no memory of the row before | Items are placed into a fixed grid; rows and columns stay aligned |
| Typical use | Navbar, button group, form row, centering one item | Page shell, image gallery, card grid, dashboard |
| Browser support | Universal, no prefixes needed | Universal, no prefixes needed |
When Flexbox is the right call
Reach for Flexbox when you’re aligning a handful of items along one line and want them to size themselves based on content:
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
gap: 1rem;
}
That’s a navbar: logo on the left, links on the right, everything vertically centered, done. No grid tracks to define, no wasted setup for something this small.
Other jobs Flexbox is genuinely the better tool for:
- Centering a single item vertically and horizontally
- A row of buttons or tags that should wrap naturally when space runs out
- Distributing space between a fixed number of items with
space-between - Form rows where a label and input sit side by side
- The inside of a card — image, title, description, button pinned to the bottom with
margin-top: auto
When Grid is the right call
Reach for Grid when the layout itself has structure — actual rows and columns that need to relate to each other:
.page {
display: grid;
grid-template-columns: 240px 1fr;
grid-template-areas:
"sidebar header"
"sidebar main";
min-height: 100vh;
}
That’s a sidebar layout defined in four lines, with named areas instead of nth-child guesswork. Try building that with Flexbox and you’ll end up faking columns with fixed widths and margins — it’ll work, but you’re fighting the tool.
Grid is the better tool for:
- Page-level layout: header, sidebar, main content, footer
- Card grids where every card should line up in equal-height rows and columns
- Image galleries with a fixed-track or masonry-style layout
- Dashboards with panels of different sizes sharing the same underlying grid
- Anything where you’d otherwise need
nth-childselectors to fake column alignment
For equal-width cards that reflow automatically without a single media query, this is the pattern to know:
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: 1.5rem;
}
auto-fit and minmax() together mean the browser works out how many columns fit at the current width — no breakpoints to maintain.
You don’t have to pick one
This is the part that gets skipped in most explainers: production layouts almost always use both, at different levels.
Grid defines the macro structure — the page shell, the card grid, the overall skeleton. Flexbox handles the micro alignment inside each of those grid cells — the contents of a single card, the row of icons in a footer column. Neither tool replaces the other; they solve different-sized problems in the same layout.
If you’re nesting a grid inside a grid and want the inner grid’s tracks to actually line up with the outer one — useful when a card’s image, title and button need to align across cards even if descriptions run different lengths — subgrid is the tool for that. It reached Baseline widely-available status across browsers in March 2026, so it’s now safe to use in production without a fallback.
The decision checklist
| flexbox | Aligning items along one row or column |
| grid | Building the page skeleton — header, nav, main, aside, footer |
| flexbox | Content of unknown length that should wrap naturally, like tags or chips |
| grid | Rows and columns need to visually line up with each other |
| flexbox | Laying out what’s inside a single grid cell or card |
Common mistakes
Using Flexbox for a full page layout
It basically works until the content doesn’t cooperate — then you’re adding wrapper divs and fixed widths to fake what Grid does natively.
Using Grid for a simple row of three buttons
It works, but it’s more setup than the problem needs. If you’re only ever thinking about one direction, you don’t need two-dimensional tooling.
Expecting flex-wrap to keep columns aligned
It won’t — that’s the four-card problem from the top of this post. Wrapped Flexbox rows have no relationship to each other. If alignment across rows matters, that’s your signal to switch to Grid.
Forgetting gap works on both
You don’t need margin hacks on either one anymore — gap handles spacing between items in Flexbox and between tracks in Grid, without adding extra space around the outer edge the way margins can.
Build the Flexbox part without doing the math by hand
Set direction, alignment and wrapping visually and copy the generated CSS straight out — or start with the fundamentals if you want the full property list first.
