Flexbox or Grid: choosing
The usual advice is "Flexbox for one dimension, Grid for two". That is correct and it is not quite enough to decide with, because most real layouts could be built either way. This lesson is the sharper question to ask instead.
The question that actually decides it
Does the content decide the layout, or does the layout decide the content?
- Flexbox is content-out. You give it items and it distributes space according to what they need. A row of tags of different lengths, a button bar, a navigation menu — the items' own sizes drive the result.
- Grid is layout-in. You define the tracks first and items go into them. A page skeleton, a photo gallery, a form of labels and fields — you decided the structure before you knew the content.
So: if you can draw the layout on paper before you know what goes in it, use Grid. If the layout is whatever the items happen to need, use Flexbox.
Where each one clearly wins
Flexbox:
.tags { display: flex; flex-wrap: wrap; gap: 0.5rem; }
Tags of unpredictable widths wrapping naturally. In Grid they would be forced into columns of equal width, which looks wrong.
.card { display: flex; flex-direction: column; }
.card__footer { margin-top: auto; }
Pushing one item to the far end of its axis. margin-top: auto and
margin-left: auto are Flexbox tricks with no neat Grid equivalent.
.header { display: flex; justify-content: space-between; align-items: center; }
Two or three things at the ends of a bar.
Grid:
.page {
display: grid;
grid-template-areas: "header header" "sidebar main" "footer footer";
}
A page skeleton, where the named areas are a picture of the layout.
.cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
A collection of equal-width cards, responsive with no media queries.
.form { display: grid; grid-template-columns: max-content 1fr; gap: 0.5rem 1rem; }
Alignment in both directions at once. This is the real dividing line: every label right-aligned to the same edge and every field starting at the same x, across rows. Flexbox cannot do that — each flex row knows nothing about the others, so the label column will not line up. If you find yourself setting a fixed width on something to make columns align across rows, you want Grid.
The one-dimensional case where Grid is still better
/* Flexbox: the columns are not equal if the content differs */
.row { display: flex; gap: 1rem; }
.row > * { flex: 1; }
/* Grid: exactly equal, guaranteed */
.row { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1rem; }
flex: 1 gets you close, and it distributes the leftover space after each item's
content minimum — so a column with a long word ends up wider. Grid's tracks are sized
before the content is considered, so they are genuinely equal.
If "exactly equal columns" matters, use Grid even for a single row.
Use both
The answer in almost every real component:
.cards { /* Grid: the arrangement */
display: grid;
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
gap: 1.5rem;
}
.card { /* Flexbox: inside one card */
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.card__meta { /* Flexbox again: a row inside the card */
display: flex;
justify-content: space-between;
align-items: baseline;
}
Grid for the page and the collection, Flexbox for the inside of a component. You will write this shape constantly. Nesting a flex container inside a grid item is normal and costs nothing.
Things they share
Worth knowing so you do not learn them twice:
gapworks identically in both.align-items,align-self,justify-contentwork in both, with the same meanings relative to each one's axes.place-itemsandplace-contentwork in Grid; in Flexboxjustify-itemsis ignored, soplace-itemsonly does half a job.orderworks in both, and carries the same accessibility warning in both.- Both ignore whitespace between children, so the inline-gap problem from the first lesson of this module disappears either way.
Things only one can do
| Only Flexbox | Only Grid |
|---|---|
margin-left: auto to push one item away |
Align items across both axes at once |
| Wrapping items at their natural widths | grid-template-areas as a readable map |
flex-shrink — items giving up space unevenly |
Overlapping items in the same cell |
baseline alignment across a row of mixed sizes |
auto-fit/auto-fill responsive tracks |
subgrid, for aligning the insides of siblings |
Overlapping is the underrated Grid feature. Two items placed in the same cell
stack, so a caption over a photo needs no position: absolute and no positioned
ancestor:
.hero { display: grid; }
.hero > * { grid-area: 1 / 1; } /* both in the same cell */
.hero__caption { align-self: end; justify-self: start; }
What not to worry about
Browser support. Both are supported everywhere you care about. Flexbox has been safe for a decade; Grid for about eight years. Tutorials that hedge about it are old.
Performance. Neither is meaningfully slower than the other, and neither is slower than the float-based layouts they replaced. Choose on clarity.
Doing it "the right way". A layout built with the other one is not wrong if it reads clearly and holds up when the content changes. The cost of the wrong choice is usually a few extra declarations, not a broken page.
A decision list
Is it the overall page skeleton? -> Grid, with named areas
A collection of similar cards? -> Grid, auto-fit + minmax
Labels and fields aligned across rows? -> Grid
Do items need to line up with items in other rows? -> Grid
Exactly equal columns, regardless of content? -> Grid
Items overlapping in the same space? -> Grid
A single row or column of things? -> Flexbox
Items of unpredictable width that should wrap? -> Flexbox
One item pushed to the end? -> Flexbox
Aligning text baselines across mixed sizes? -> Flexbox
The inside of a component? -> Flexbox
Text wrapping around an image? -> float
Things just stacked down the page? -> normal flow, write nothing
That last line is still the one people forget most.
Check your work
The sharper question. Does the content decide the layout, or the layout decide the content?
The paper test. If you can draw it before knowing the content, use Grid.
The real dividing line. Alignment across rows — Flexbox rows know nothing about each other.
When Grid wins in one dimension. When the columns must be exactly equal; flex: 1
distributes leftover space and content still affects width.
What Flexbox can do that Grid cannot. auto margins to push an item, wrapping at
natural widths, uneven shrinking, and baseline across a row.
What Grid can do that Flexbox cannot. Two-axis alignment, named areas,
overlapping items, auto-fit, subgrid.
Where place-items only half works. Flexbox, because justify-items is ignored.
How to overlap two items without positioning. Put both in the same grid cell with
grid-area: 1 / 1.
What not to worry about. Support and performance. Choose on clarity.
Practice
- Build a row of tags of varying lengths in Flexbox, then in Grid. Decide which looks right and say why.
- Build a label-and-field form in Flexbox and try to make the labels line up across
rows. Then do it in Grid with
max-content 1fr. - Build three columns with
flex: 1where one contains a long word. Measure the widths, then switch tominmax(0, 1fr). - Build a card collection in Grid with a Flexbox card inside. Vary the text lengths.
- Push a card's footer to the bottom with
margin-top: auto, then try to achieve the same thing in Grid. - Overlap a caption on a photo using one grid cell, then again with
position: absolute. Compare the amount of CSS. - Align a price and a label by
baselinein Flexbox, then attempt it in Grid. - Take the decision list and, for each line, build the smallest example you can.
- Find a layout on a real site, inspect it, and work out which of the two they used. Then decide whether you would have chosen the same.
- Rebuild one section of your own page with the other tool. Note what got harder.
Official documentation
- MDN — Relationship of Grid layout to other layout methods — The specification authors' own comparison, including where the two overlap deliberately.
- MDN — Realising common layouts using grids — Worked page layouts, with the Flexbox alternative shown for each.
- MDN — CSS layout cookbook — Recipes for the patterns in this lesson, each with the reasoning for the method chosen.
Next: why z-index sometimes does nothing at all.
Stuck on this lesson?
Being stuck is part of it — but being stuck alone for three days is not. Our internship programme pairs this curriculum with code review and one-to-one help from working developers, and it is free.
About the internship