Flexbox and Grid
One question decides between them: is the layout one-dimensional or two? Flexbox distributes items along a single axis; Grid places them into rows and columns that exist whether or not anything fills them.
Flexbox: one axis, content-driven
.toolbar {
display: flex;
align-items: center; /* cross axis */
justify-content: space-between; /* main axis */
gap: 1rem;
}justify-* works on the main axis and align-* on the cross axis.
Setting flex-direction: column swaps which is which — that is the single most
common source of “why is align-items doing nothing”.
The shorthand is where the real behaviour lives:
.item { flex: 1; } /* = 1 1 0% grow, shrink, basis */
.item { flex: auto; } /* = 1 1 auto — starts from content size */
.item { flex: none; } /* = 0 0 auto — never resizes */flex: 1 versus flex: auto is a real interview question. With flex: 1 the
basis is 0%, so items share the container equally regardless of content.
With flex: auto the basis is the content width, so items keep their natural
proportions and only share the leftover space.
Gotcha: a flex item will not shrink below its content’s minimum size, because
min-widthdefaults toauto. That is why a long string or a<pre>blows out a flex layout, and whymin-width: 0is the fix that looks like a hack and is not.
Grid: two axes, container-driven
.layout {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
gap: 1rem;
}That one line is responsive without a media query: as many 240px-minimum
columns as fit, sharing the space equally. auto-fill leaves empty tracks;
auto-fit collapses them so the existing items stretch — the difference shows
only when there are fewer items than columns.
Named areas make a page layout readable:
.page {
display: grid;
grid-template-areas:
"header header"
"nav main"
"footer footer";
grid-template-columns: 200px 1fr;
}
.page > nav { grid-area: nav; }fr is a unit only Grid has: a fraction of the remaining space, after
fixed tracks and gaps are subtracted. 1fr is not 50% — percentages do not
account for the gap, which is why a two-column 50% 50% layout with a gap
overflows and 1fr 1fr does not.
Choosing
| Situation | Use |
|---|---|
| A row of buttons, a nav bar | flex |
| Content decides the sizes | flex |
| Wrapping cards, equal columns | grid |
| A page skeleton | grid |
| Overlapping items | grid |
Grid for the page, flex for the components is the usual split, and they nest freely — a grid cell containing a flex row is normal.
Grid can also overlap, which flex cannot: place two items in the same
grid-area and they stack, which is a cleaner way to layer a caption over an
image than absolute positioning.
Centring, finally solved
.parent { display: grid; place-items: center; }Two lines, any content, any size, both axes. The older answers — absolute
positioning with transforms, table-cell, flex with justify and align — all
still work and none are shorter.
For the “centre one child but not the others” case:
.parent { display: grid; }
.child { place-self: center; }gap replaced margin hacks
gap works in flex, grid and multi-column, and it applies only between
items — no trailing margin on the last one, no :last-child { margin: 0 }
override. Any layout code still using margin-right for spacing between flex
items predates it.
What is next
Subgrid lets a nested grid align to its parent’s tracks, which solves card layouts where headers and footers must line up across cards of different content lengths — the classic failure of nested grids.
Container queries let a component respond to its own width rather than the viewport’s, so the same card works in a sidebar and a full-width row. Both are in Container Queries and Subgrid, and together they are the biggest layout shift since Grid itself.
Related
Interview angle 6
- “Flexbox or Grid?” - one dimension or two. Flex distributes items along a single axis and is content-driven; Grid defines rows and columns that exist regardless of content. Grid for the page skeleton, flex for the components inside it, nested freely.
- “What’s the difference between
flex: 1andflex: auto?” - the basis.flex: 1is1 1 0%, so items share the container equally whatever their content.flex: autois1 1 auto, so items keep their natural size and share only the leftover space. - “A long string breaks my flex layout. Why?” - a flex item’s
min-widthdefaults toauto, so it refuses to shrink below its content’s minimum.min-width: 0on the item is the fix, and it is a genuine part of the spec rather than a hack. - “How do you build a responsive card grid without media queries?” -
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)).auto-fitinstead ofauto-fillcollapses empty tracks so existing items stretch to fill. - “Why use
1frrather than50%?” -frdivides the space remaining after fixed tracks and gaps. Percentages ignore the gap, so50% 50%plus a gap overflows the container while1fr 1frdoes not. - “How do you centre something?” -
display: grid; place-items: centeron the parent. Two lines, both axes, any content size. Useplace-selfon the child if only one item should be centred.