Flexbox
Date: 2026-09-27
Flexbox lays items out along one axis. It starts each item at its
flex-basis, then shares out the leftover space byflex-grow, or the overflow byflex-shrink. Nearly every confusing flex result is that arithmetic, plus the hiddenmin-width: autothat stops items shrinking below their content.
Flexbox is a one-dimensional layout mode: a flex container places its children in a row or column, and distributes space between them according to each item’s flex values. One-dimensional means it reasons about one line at a time — even when items wrap, each line is sized independently of the others, which is the real difference from Grid.
The two axes
flex-direction: row
main axis ─────────────────────────────────────▶ justify-content
┌──────┐ ┌────────────┐ ┌────┐ (distributes along)
│ A │ │ B │ │ C │ ▲
└──────┘ └────────────┘ └────┘ │ cross axis align-items
▼ (aligns across)
justify-* is the main axis, align-* is the cross axis. Change flex-direction to column and they swap physical directions — which is why “justify-content: center doesn’t centre vertically” in a row container.
The algorithm
flex is shorthand for three values: grow shrink basis.
container 600px, three items, no gap
basis grow shrink
A flex: 0 1 auto 100 0 1 ← content width 100
B flex: 1 1 0 0 1 1
C flex: 2 1 0 0 2 1
step 1 sum of bases 100 + 0 + 0 = 100
step 2 free space 600 − 100 = 500
step 3 share by grow B gets 1/3 × 500 = 167
C gets 2/3 × 500 = 333
result A 100 · B 167 · C 333
flex-grow shares out free space, not total width. flex: 1 and flex: 2 only give a 1:2 ratio of total width when both bases are zero — which is exactly what the shorthand does:
flex: 1 → 1 1 0% basis 0: widths split purely by ratio
flex: auto → 1 1 auto basis = content: bigger content, bigger item
flex: none → 0 0 auto rigid: content size, never grows or shrinks
(default) → 0 1 auto content size, can shrink, won't grow
Shrinking works the same way in reverse, except overflow is shared out weighted by basis × shrink, so larger items give up more.
The minimum-size trap
A flex item’s min-width defaults to auto, which means it won’t shrink below its content’s minimum width — the longest word, a wide image, a pre block, or a child with white-space: nowrap.
/* a sidebar + main layout where main contains a long URL or a code block */
.layout { display: flex; }
.sidebar { flex: 0 0 240px; }
.main { flex: 1; min-width: 0; } /* ← without this, main refuses to shrink
and the page scrolls sideways */min-width: 0 (or overflow: hidden) on the flexible item is the fix for most “flex item is overflowing its container” bugs. The column equivalent is min-height: 0, and it’s why nested scrolling panels don’t scroll.
Flex or grid
| Use flexbox when | Use grid when |
|---|---|
| The content decides the size — nav items, tags, a button with an icon | The layout decides the size — columns that line up |
| One row or column, or wrapped rows that don’t need to align | Items in different rows must align with each other |
Pushing one item away: margin-left: auto | Placing items into named regions |
Wrapped flex rows are the tell: if you’re setting width: 33.33% on items to make wrapped rows line up, you wanted grid.
Failure modes
- Overflow from
min-width: auto, above. The most common flex bug by a distance widthon a flex item is only a suggestion. It feedsflex-basis: autobut shrinking still applies; useflex-basisorflex: 0 0 Xif it must be fixed- Visual order ≠ DOM order.
orderandflex-direction: row-reversemove things visually, but keyboard focus and screen readers follow the source — Keyboard Navigation - Percentage heights inside flex columns that resolve to nothing because the container has no definite height
Where it connects
- The Box Model — margins don’t collapse inside a flex container
- Grid — the two-dimensional counterpart
- Logical Properties —
rowalready follows writing direction; flex was logical before the logical properties existed