I used to Google "css grid vs flexbox" at the start of every new layout. Not because I didn't understand them — I did — but because in the heat of building something, I second-guessed myself every time. Eventually I sat down and mapped out the decision framework I kept arriving at. This article is that map.
The short answer is: Flexbox for components, Grid for layouts. But that's oversimplified. The real answer lives in a single question: are you arranging items along one axis, or controlling them across two?
"The mistake isn't choosing the wrong one — it's forcing one to do the job of the other."
The Core Difference: 1D vs 2D
This is the one thing worth memorising. Flexbox works in one dimension at a time — either a row or a column. Grid works in two dimensions simultaneously — rows and columns at the same time.
The visual difference matters: with Grid, the container defines the structure. Cells exist in the grid whether or not they have content. With Flex, the items define the structure — the container just manages their flow.
When to Use Flexbox
Flexbox excels when you need items to flow in a line and you want them to be flexible about how they fill that space. Use it for:
- → Navigation bars — logo on left, links in the middle, CTA on right. One row, items spread apart.
- → Button groups — icon + label inside a button, or a row of action buttons that wrap on small screens.
- → Card body layout — avatar + text block side by side, or a column of text/meta/CTA inside a card.
-
→
Form rows — label and input on one line, or stacked inputs that stack on mobile via
flex-wrap. -
→
Centering anything —
display:flex; align-items:center; justify-content:centeris still the cleanest centering method.
/* Navigation bar */ .nav { display: flex; align-items: center; justify-content: space-between; gap: 1rem; } /* Items inside can grow/shrink naturally */ .nav-links { display: flex; gap: 2rem; list-style: none; }
When to Use CSS Grid
Grid is the right tool when the layout needs to exist independently of the content. You're defining columns and rows as a structure, then placing things into it.
| Layout Pattern | Flexbox | Grid |
|---|---|---|
| Page-level layout (sidebar + main) | ✗ Awkward | ✓ Perfect |
| Card grids (equal column widths) | ✗ Needs hacks | ✓ Native |
| Nav bar (logo + links + cta) | ✓ Ideal | ✗ Overkill |
| Items that span multiple rows/columns | ✗ Not possible | ✓ grid-column/row |
| Centering a single element | ✓ Simpler | ✓ Also works |
| List of buttons/tags that wrap | ✓ flex-wrap | ✗ Wrong tool |
| Holy Grail layout (header/sidebar/main/footer) | ✗ Complex | ✓ Elegant |
/* Page shell with sidebar */ .page-layout { display: grid; grid-template-columns: 1fr 300px; gap: 3rem; } /* Responsive card grid */ .card-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 1.5rem; }
The Decision Framework
Ask these questions in order:
If yes → Grid immediately. Don't debate it.
Page-level structure → Grid. Think header, main, sidebar, footer as named areas.
Single-axis flow → Flexbox. Nav bars, button rows, tag lists, inline icon+label components.
Spanning rows or columns → Grid. A featured card spanning 2 columns, a sidebar spanning the full page height.
Content-driven (items determine size) → Flexbox. Space-driven (columns/rows pre-defined) → Grid.
Use Both. Grid for the outer shell, Flexbox inside each card. They compose perfectly — there's no rule against nesting them.
How This Portfolio Uses Both
This very site is a good example of composition. The page-level structure (header, hero,
sections, footer) uses Grid in places where multiple columns need to align. The nav bar
is Flexbox. The project cards grid is Grid with auto-fit. Inside each project card, the
badge + title + description stack is Flexbox. Inside each section's tag + title group, it's Flexbox.
Choosing between them is never an either-or. It's about matching the tool to the problem at the specific level of the component hierarchy you're working on. Page → Grid. Component → Flexbox. Content inside that component → probably Flexbox again.
