Flexbox is the workhorse layout of the modern web: toolbars, menus, cards, forms, "push the button to the right", "center this" — all of it is flexbox. The model is one-dimensional: the container lays out its children along a single axis and can flexibly distribute space between them. The key to understanding it is the axes and the three flexibility properties.
Container, axes, and direction
display: flex on a container enables the layout for its direct children:
.toolbar { display: flex; }
Children line up along the main axis; perpendicular to it is the cross axis. Where the main axis points is set by flex-direction: row (default, left to right), column (top to bottom), plus the reversed variants. Every property that follows is tied to the axes, not to the sides of the screen — change the direction, and "horizontal" alignment becomes vertical. That's not a quirk but a strength: the same logic lays out both a toolbar row and a sidebar column.
By default children don't wrap and are allowed to shrink; flex-wrap: wrap permits wrapping onto new lines — that's how fluid galleries of tags and cards are built.
Alignment: justify vs align
The pair that gets confused every time differs by axis:
justify-content— distribution along the main axis:flex-start,center,flex-end,space-between(edge items against the edges, the rest split evenly between),space-around,space-evenly.align-items— alignment along the cross axis:stretch(default — stretch to the row height),center,flex-start,flex-end,baseline(along the text baseline — for rows with different font sizes).
.header {
display: flex;
justify-content: space-between; /* logo to the left, menu to the right */
align-items: center; /* everything vertically centered */
}
Perfect centering, which the web wrestled with for a decade, is three lines: display: flex; justify-content: center; align-items: center.
Precision tools: align-self overrides align-items for a single child; margin-left: auto on a child eats all the free space on its left — the idiom for "push the last item to the opposite edge" without wrappers. order changes the visual order without touching the markup (careful: tab order and screen reader order still follow the DOM — the mismatch hurts accessibility).
Spacing between children is the gap property: honest gaps only between items, without margin hacks and without "eating" the outer edges. Together with flex-wrap it also sets the spacing between lines.
Flexibility: grow, shrink, basis
The heart of flexbox is how children divide space. Each child has a trio of properties:
flex-basis— the starting size along the main axis (before distribution);auto— from the content.flex-grow— the share of free space the child takes (0 — doesn't grow).flex-shrink— willingness to shrink when space runs out (1 by default — everyone shrinks).
They're written with the shorthand flex: grow shrink basis. Three presets cover 95% of cases:
.item-a { flex: none; } /* 0 0 auto — rigid: sized by content, doesn't grow, doesn't shrink */
.item-b { flex: auto; } /* 1 1 auto — from content, extra space shared proportionally */
.item-c { flex: 1; } /* 1 1 0 — EQUAL columns: start from zero, split everything */
The difference between flex: auto and flex: 1 is the basis: auto divides only the free space (whoever was bigger by content stays bigger), while flex: 1 zeroes out the starting sizes and divides everything — the columns come out strictly equal. The classic — "the input takes everything, the button takes its own size":
.search { display: flex; gap: 8px; }
.search input { flex: 1; }
.search button { flex: none; }
Overflow and min-width: 0
The most famous flexbox gotcha. A long unbroken string (a URL, code) sits inside a flex: 1 column — and the column refuses to shrink, breaking the layout. The reason: flex children have min-width: auto — "no narrower than my content". The cure — allow shrinking:
.column { flex: 1; min-width: 0; }
.column .title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
Without min-width: 0, ellipsis text truncation inside flex columns doesn't work either — now you know why.
In short
- Flex is a one-dimensional layout: a main axis (direction) and a cross axis. All properties are tied to the axes, not the sides of the screen.
- justify-content — along the main axis, align-items — across it. Centering anything is three lines.
- The flexibility trio: basis (start), grow (share of free space), shrink (shrinkability).
flex: 1— equal columns,flex: none— a rigid item,flex: auto— content-sized with proportional extra. - gap instead of margin hacks;
margin-left: auto— push an item to the edge; order changes only the visual order (accessibility!). - Not shrinking / ellipsis not working — set
min-width: 0on the flex child.
What to read next
- Grid — two-dimensional layout: when there are many rows and columns and they're related.
- Positioning — the previous topic in the series.
- The box model — why margins don't collapse inside a flex container.