CSS Grid vs Flexbox: When to Use Which
Use CSS Grid for two-dimensional layouts — rows and columns together, like page skeletons and card galleries — and Flexbox for one-dimensional layouts — a single row or column of items, like a navbar or a row of buttons. Build either layout visually with our free CSS grid generator; side-by-side examples and the full decision rule are below.
One dimension vs two: the real difference
Flexbox lays items out along one axis — either a row or a column. It is brilliant at distributing a set of items inside a single line: centering a button, spacing navbar links, or pushing one item to the far end. CSS Grid lays items out along two axes at once — rows and columns. It is built for layouts where the relationship between rows and columns matters: a 12-card gallery, a page skeleton with header, sidebar, main content, and footer, or a dashboard where a chart needs to span exactly two columns and three rows. The mental model that helps most developers: Flexbox aligns content inside a line; Grid defines the lines themselves. On a 960-pixel page with three equal columns and a 24-pixel gap, Grid computes each column as (960 − 48) ÷ 3 = 304 pixels for you — try expressing that relationship in Flexbox and you end up fighting width percentages and margins on every breakpoint. Grid also lets you overlap items in named cells, reorder regions visually without touching HTML, and size tracks with minmax() so columns stay within sane bounds. Flexbox does none of that, but it does something Grid cannot: it lets content dictate the layout — a row of tags that wraps naturally, a toolbar that collapses gracefully, a badge that hugs its text. If your design question starts with 'I have these items in a line,' reach for Flexbox; if it starts with 'I have this page,' reach for Grid.
The one-line decision rule
Ask yourself: can I draw this layout as one line? A navbar with a logo on the left and links on the right is one line. A pricing page with three plan cards in a row is one line. A footer with four stacked link columns is arguably one line of four groups — but those groups themselves form columns, which is where developers start reaching for Grid. If the answer is yes, use Flexbox: display: flex; justify-content: space-between; align-items: center; handles the navbar in three declarations. If the answer is no — the header spans the full width, the sidebar is 280 pixels wide, the main content fills the rest, and a footer closes the page — use Grid: grid-template-columns: 280px 1fr; with named areas. The rule survives edge cases well. A card gallery with 12 cards is visually two-dimensional even though it is conceptually 'a list of cards' — because cards must line up into tidy rows and columns, Grid's repeat(auto-fill, minmax(240px, 1fr)) pattern wins over Flexbox's wrapping row, which leaves ragged right edges. Conversely, a breadcrumb trail or a row of social icons is one-dimensional even inside a big page — Flexbox keeps it compact. For a worked comparison of a second layout primitive, see our guide on building gradients with three colors, which pairs the same visual-builder approach with a different CSS output. For the documentation around your layouts, convert component docs with our markdown to HTML converter, and check any copy length with the word counter before it ships.
Side-by-side code examples
Here is the same navbar in both systems. Flexbox: .nav { display: flex; justify-content: space-between; align-items: center; } — three lines, done, and the logo and links push apart automatically. Grid can do it with grid-template-columns: auto 1fr auto; but gains you nothing. Now the gallery. Flexbox version: .gallery { display: flex; flex-wrap: wrap; gap: 24px; } .card { flex: 0 0 calc(33.333% − 16px); } — and every time the gap changes you must recompute the calc(), and the last row's cards stretch or leave gaps. Grid version: .gallery { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 24px; } — two lines, responsive from a 360-pixel phone (one column) to a 1440-pixel monitor (five columns), no calc, no media queries. And the page skeleton, which only Grid handles cleanly: grid-template-areas: 'header header' 'sidebar main' 'footer footer'; grid-template-columns: 280px 1fr; maps four regions in two declarations. When you need a layout like that without hand-writing it, a visual CSS grid generator produces the same declarations from a drag-and-drop preview. Pairing layout builders with other front-end utilities helps too — see how to generate open-graph meta tags for the social-sharing layer that sits on top of any finished layout.
Three mistakes that mix them up
Mistake one: using Flexbox for page skeletons. Developers build a header-sidebar-main-footer page with nested flex containers, then spend a week fighting heights: the sidebar will not stretch to full page height, the footer will not stick to the bottom when content is short. Grid's grid-template-rows: auto 1fr auto; solves both in one line. Mistake two: using Grid for a single row of items. A toolbar with display: grid; grid-template-columns: repeat(5, auto); works, but the moment one item wraps or a badge is added, Flexbox's content-aware wrapping was the right call — three declarations instead of five, and it adapts when the text changes. Mistake three: nesting both without a reason. The best layouts usually combine the two: Grid defines the page skeleton or the gallery, and Flexbox aligns content inside each cell — centering a button in a card, distributing navbar links. The classic anti-pattern is a flex container whose only job is to fake two-dimensional alignment with negative margins, or a grid whose only job is one row. Check your markup: if a container has exactly one row and never wraps, swap it to Flexbox; if it has rows and columns, swap it to Grid. Getting this instinct right saves more layout debugging time than any other CSS skill, and it is the first thing every front-end interview will probe.