The Short Version
Flexbox lays out items along one axis at a time. Grid lays them out along two axes at once. That single distinction drives almost every layout decision you will make between them.
Reach for Flexbox when content should flow in a line and the number of items is flexible or unknown. Reach for Grid when you want to place items into a defined structure of rows and columns, with explicit positions.
Flexbox Basics: One Dimension
Flexbox works on a main axis and a cross axis. You set `flex-direction` to choose which way items flow, and everything else falls out from there.
.nav {
display: flex;
flex-direction: row; /* main axis is horizontal */
justify-content: space-between;
align-items: center;
gap: 1rem;
}
Key properties:
- `flex-direction` picks the main axis (`row` or `column`).
- `justify-content` aligns items along the main axis.
- `align-items` aligns items along the cross axis.
- `gap` spaces items without margins.
- `flex` on a child controls grow, shrink, and basis.
Flexbox is content-first. It distributes available space based on what items need. When you do not know how many items you have, or when they should wrap naturally, Flexbox handles it gracefully with `flex-wrap: wrap`.
.chips {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
A row of tags, a button group, a toolbar, a media object with an icon and text: all classic Flexbox jobs.
Grid Basics: Two Dimensions
Grid works on rows and columns at the same time. You define tracks, then place items into them.
.gallery {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: auto;
gap: 1.5rem;
}
Key properties:
- `grid-template-columns` and `grid-template-rows` define the tracks.
- `gap` spaces tracks apart.
- `grid-column` and `grid-row` place a child at a specific location or span.
- `repeat()` and the `fr` unit size tracks flexibly.
- `minmax()` sets a floor and ceiling for track size.
Grid is layout-first. You decide the structure, then drop content into it. When you want a predictable grid of cards, a photo gallery, or a full page template, Grid makes the intent explicit.
The single most useful modern pattern is the auto-fitting, responsive grid:
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: 1rem;
}
This one rule builds a card grid that adds columns on wide screens and removes them on narrow ones, with no media query. Each card is at least 240px wide, and remaining space is shared evenly.
When to Use Each
Use Flexbox for:
- Navbars and toolbars with a start, middle, and end group.
- Button rows and chip lists that wrap.
- Centering a single item, both axes at once.
- Media objects: an image next to text where the text should fill remaining space.
- Any row or column whose item count varies.
Use Grid for:
- Card layouts and photo galleries with fixed columns.
- Full page templates with header, sidebar, main, and footer regions.
- Forms with aligned label and input columns.
- Any layout where you need to control both rows and columns, or span items across them.
The mental shortcut: if you think in terms of a line, use Flexbox. If you think in terms of a grid of cells, use Grid.
Combining Both
The two systems are not rivals. Real layouts mix them, with Grid handling the page structure and Flexbox handling the pieces inside each region.
.page {
display: grid;
grid-template-areas:
"header header"
"sidebar main"
"footer footer";
grid-template-columns: 240px 1fr;
grid-template-rows: auto 1fr auto;
min-height: 100vh;
}
.header { grid-area: header; display: flex; justify-content: space-between; align-items: center; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.footer { grid-area: footer; display: flex; justify-content: center; }
The page itself is a Grid. The header is a Flexbox row. The footer is a centered Flexbox row. Each tool does the job it does best.
Real-World Layout Patterns
Navbar with Flexbox
.navbar {
display: flex;
align-items: center;
gap: 1rem;
}
.navbar .brand { margin-right: auto; } /* pushes the rest to the right */
.navbar .links { display: flex; gap: 1rem; }
`margin-right: auto` on the brand is the trick. It eats all remaining space and shoves everything else to the right edge.
Card Grid with Grid
.cards {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
gap: 1.25rem;
}
`auto-fill` keeps empty tracks reserved when items run out, `auto-fit` collapses them. Most of the time you want `auto-fit`.
Holy Grail Layout with Grid
The classic header, footer, three-column body in one declaration.
.holy-grail {
display: grid;
grid-template:
"header header header" auto
"left main right" 1fr
"footer footer footer" auto
/ 200px 1fr 200px;
min-height: 100vh;
gap: 1rem;
}
.header { grid-area: header; }
.left { grid-area: left; }
.main { grid-area: main; }
.right { grid-area: right; }
.footer { grid-area: footer; }
Grid template areas read like a picture of the layout. That clarity is why this pattern moved from difficult to trivial.
Centering with Flexbox
The classic problem, now one line.
.center {
display: flex;
place-items: center; /* align-items + justify-content */
min-height: 100vh;
}
`place-items` is the shorthand that centers on both axes. Use it whenever something must sit dead center.
Browser Support
Both Flexbox and Grid are baseline-stable in every modern browser. Grid gap, subgrid, and `aspect-ratio` all ship in current Chrome, Firefox, Safari, and Edge. The only browsers that struggle are very old releases that are no longer supported by their vendors.
Subgrid, the feature that lets a child follow the parent's tracks, is the newest piece. It landed in all major engines in 2023. It unlocks aligned card content, multi-column lists, and form fields that share column lines, all without hacks.
You no longer need a fallback strategy for Flexbox or core Grid. Use them directly. Add subgrid where it helps, and ship.
Responsive Design Approaches
The two systems respond to viewport changes differently.
Flexbox with `flex-wrap` reflows items into rows on their own. No breakpoints needed for simple wrapping.
Grid with `auto-fit` and `minmax` reflows columns on their own. The card grid above is fully responsive with zero media queries.
For layouts that must restructure, combine techniques. Start with a Grid that has named areas for the desktop view, then override the template inside a media query to stack regions on narrow screens.
.page { /* desktop: two columns */ }
@media (max-width: 720px) {
.page {
grid-template-areas:
"header"
"main"
"sidebar"
"footer";
grid-template-columns: 1fr;
}
}
The grid stays the same, only the template changes. That is the cleanest responsive pattern available.
A Practical Decision Flow
1. Are you laying out items in a single row or column? Use Flexbox.
2. Do you need to control both rows and columns, or span items across them? Use Grid.
3. Is the item count unknown or flexible? Lean Flexbox with `flex-wrap`.
4. Do you want a fixed number of responsive columns with no media queries? Lean Grid with `auto-fit` and `minmax`.
5. Building a full page template? Use Grid for the page, Flexbox inside each region.
Most layouts answer question one or question two immediately. When the answer is both, combine the systems.
Layout Meets Visual Style
A solid layout is the skeleton. Visual fill is what makes a design feel finished. After your flex and grid structure is in place, layer in backgrounds with the [CSS gradient generator](/en/css-gradient). Gradients sit cleanly inside any grid cell or flex container, scale with the element, and never add a network request. Pair a tidy responsive grid with a thoughtful gradient and you have a polished section with only a few lines of CSS.