Flexbox fundamentals — one-dimensional layout
Flexbox solves exactly one problem — distributing space among items along a single axis — and nearly every confusing flexbox behavior traces back to the difference between the main axis and the cross axis.
3 min read
The one problem flexbox actually solves
.toolbar {
display: flex;
justify-content: space-between; /* spread items along the MAIN axis */
align-items: center; /* center items along the CROSS axis */
}Flexbox exists to answer one question well: given a row (or column) of items and some available space, how should that space be distributed among them? It's deliberately one-dimensional — it reasons about a single axis at a time, which is exactly what makes it the right tool for a toolbar, a nav bar, or a row of buttons, and the wrong tool for a full page grid with both rows and columns that need to align together (that's the next lesson's job).
The main axis and cross axis: the single idea that unlocks flexbox
.row { display: flex; flex-direction: row; } /* main axis: horizontal, cross axis: vertical */
.col { display: flex; flex-direction: column; } /* main axis: vertical, cross axis: horizontal */Every flex property aligns items along one of exactly two axes, and which physical direction each axis points depends entirely on flex-direction. justify-content always controls the main axis (the direction items flow in); align-items always controls the cross axis (perpendicular to that). This is the single fact that resolves most flexbox confusion: justify-content: center centers horizontally in a row but vertically in a column — not because the property changed meaning, but because the main axis itself rotated 90 degrees.
flex-grow, flex-shrink, flex-basis: how extra (or missing) space gets divided
.sidebar { flex: 0 0 250px; } /* grow: 0 (never grow), shrink: 0 (never shrink), basis: 250px (starting size) */
.main { flex: 1 1 auto; } /* grow: 1 (take all extra space), shrink: 1, basis: auto */flex-basis sets an item's starting size before any extra/missing space gets distributed. flex-grow is a ratio, not a fixed amount: an item with flex-grow: 1 next to one with flex-grow: 2 doesn't get "1 unit" of space — it gets exactly half as much of the leftover space as its neighbor, however much leftover space there actually is. flex-shrink works the same way in reverse, for when items don't all fit. The shorthand flex: 1 (equivalent to flex: 1 1 0%) is the common "take up all available space, splitting evenly with siblings that also say flex: 1" pattern — a sidebar-plus-main-content layout, exactly as shown above, is one of flexbox's most common real uses.
gap replaced margin-juggling between flex children
/* Old way — margins on every child except the last, easy to get subtly wrong */
.item:not(:last-child) { margin-right: 16px; }
/* Modern way — one line on the flex container itself */
.toolbar { display: flex; gap: 16px; }Before gap was supported inside flex containers, spacing items evenly required margin tricks that had to specifically exclude the last child (otherwise there'd be unwanted trailing space) — a small but real source of off-by-one styling bugs. gap sets spacing between items directly on the flex container, with no such exception needed, and it's now supported in every current browser, making the old margin-exclusion pattern effectively obsolete for new code.
Further reading
Check your understanding
A quick comprehension check — not tracked, not graded, just for you.
1. What one problem does flexbox exist to solve?
2. Why does `justify-content: center` center horizontally in a row but vertically in a column?
3. What does `flex-grow: 1` on an item next to a sibling with `flex-grow: 2` actually mean?