A practical guide to CSS Grid vs Flexbox
The question "Grid or Flexbox?" comes up in almost every CSS layout decision, and the honest answer is that they were designed for different axes of a problem — most real interfaces end up using both.
The core distinction
Flexbox is **one-dimensional**: it lays items out along a single axis (row or column) and is built to distribute space and handle wrapping along that one axis. Grid is **two-dimensional**: it lets you define rows and columns simultaneously and place items anywhere in that grid, independent of source order.
If you're arranging things in a line — a navbar, a button group, a list of tags — that's Flexbox's job. If you're arranging things in a grid — a card layout, a page template with header/sidebar/content/footer — that's Grid's job.
Flexbox in practice
.navbar {
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
}Flexbox shines when the number of items is unknown and content should determine sizing — a wrapping tag list, a toolbar, a set of form controls that need to stay aligned along one line. `justify-content` controls spacing along the main axis, `align-items` controls alignment along the cross axis, and `flex-wrap` lets items fall onto new lines when they run out of room, at which point each new line becomes its own independent flex line rather than part of a shared grid.
Grid in practice
.page {
display: grid;
grid-template-columns: 240px 1fr;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"sidebar header"
"sidebar content"
"sidebar footer";
min-height: 100vh;
}Grid shines whenever rows and columns both matter — a page template, a photo gallery with consistent cells, a dashboard of cards that need to align both horizontally and vertically. `grid-template-areas` gives you a literal ASCII-art layout that's easy to read and rearrange for responsive breakpoints, and `fr` units let you distribute remaining space proportionally without doing width math.
The common pattern: Grid for structure, Flexbox for content
A typical card component uses Grid for the overall page layout and Flexbox inside each card to arrange its internal content:
.cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 1rem; }
.card { display: flex; flex-direction: column; gap: 0.5rem; }
.card__footer { display: flex; justify-content: space-between; margin-top: auto; }`repeat(auto-fill, minmax(220px, 1fr))` is one of Grid's most useful patterns: it creates as many equal-width columns of at least 220px as fit, with no media query needed for the common "responsive card grid" case.
When either would technically work
For a simple row of equally-sized items, both can do it, and the deciding factor becomes what you need next: if you'll want to control both row and column alignment independently, or place an item out of source order, reach for Grid. If it's genuinely a single line (or a single axis that wraps), Flexbox's API is simpler for that case and avoids defining a grid you don't need.
A quick decision checklist
- Two dimensions matter (rows *and* columns) → Grid.
- One dimension, content-driven sizing → Flexbox.
- Need items placed out of DOM order → Grid (`grid-column`/`grid-row`, or named areas).
- Need to center or space out items along one line → Flexbox.
- Building a page-level template → Grid, with Flexbox for the components inside it.
Try both interactively with the [Flexbox builder](/tools/html-css/flexbox-builder) and the [Grid builder](/tools/html-css/grid-builder) — toggling individual properties and watching the live preview update is the fastest way to build intuition for how each axis behaves.