Flexbox (flexible box layout) is a system built for one-dimensional arrangement: whether it is a row of navigation links, a set of equal-height cards, or an element that needs to be centered both vertically and horizontally, Flexbox solves it in a few lines of declarative code — finally ending the float-era habit of hacking layouts together.
The Main Axis and the Cross Axis
The first key to understanding Flexbox is telling the "main axis" apart from the "cross axis" — almost every flex property revolves around these two axes.
The axes with flex-direction: row (default)
↑ cross axis
1
2
3
main axis →
flex-direction decides the direction of the main axis: row (horizontal, default), column (vertical), and their -reverse variants. The cross axis is always perpendicular to the main axis — once the main axis becomes vertical, mnemonics like "justify-content controls horizontal" break down, so always think in terms of main axis / cross axis rather than "horizontal / vertical".
Container Properties
Property
Purpose
Common values
display
Enables flex layout
flex / inline-flex
flex-direction
Main axis direction
row / column / row-reverse
flex-wrap
Whether wrapping is allowed
nowrap (default) / wrap
justify-content
Main-axis alignment
flex-start / center / space-between / space-around / space-evenly
align-items
Cross-axis alignment (single line)
stretch (default) / center / flex-start / flex-end / baseline
align-content
Cross-axis alignment (multiple lines as a whole)
Same values as justify-content, requires wrap
gap
Spacing between items
e.g. 16px, or row-gap/column-gap set separately
justify-content comparison
flex-start
A
B
center
A
B
space-between
A
B
Item Properties
Property
Purpose
order
Adjusts the visual order without changing the DOM order; default 0
align-self
Overrides the container's align-items to control one item's cross-axis alignment individually
flex-grow
The ratio for distributing remaining space; default 0 (does not stretch on its own)
flex-shrink
The shrink ratio when space runs short; default 1 (allowed to shrink)
flex-basis
The "starting size" before remaining space is distributed; default auto
How grow / shrink / basis Work Together
These three are usually combined into the shorthand flex: grow shrink basis, the part of Flexbox where people most often "know the syntax but not the why". The key to understanding it is to imagine a calculation pipeline:
The browser first sums each item's "desired size" based on flex-basis;
It compares that with the container's main-axis size: if there is leftover space, it is distributed to items according to flex-grow;
If space is insufficient, items shrink according to flex-shrink (weighted by their basis).
/* Common shorthands */.item { flex: 1; } /* equivalent to 1 1 0%, evenly divides the remaining space */.item { flex: auto; } /* equivalent to 1 1 auto, stretches and shrinks with content */.item { flex: none; } /* equivalent to 0 0 auto, no flexing at all */.item { flex: 0 0 200px; } /* fixed at 200px, does not participate in flexing */
flex: 1 1 0% — three items evenly share the remaining space
flex: 1
flex: 1
flex: 1
flex: 2 1 0 / 1 1 0 / 1 1 0 — distributed in a 2:1:1 ratio
2
1
1
The gap Property
Before gap existed, spacing between items could only be cobbled together with margins, and you had to handle the edge case of "the last item needs no margin". Now gap natively supports both row and column spacing, and it never adds extra space at the container's edges.
Pattern 3: Equal-height cards with bottom-aligned buttons
.card {
display: flex;
flex-direction: column;
}
.card .spacer { flex: 1; } /* pushes the button to the bottom */
Preview: card content differs in length, but the buttons still align at the bottom
Short title
Button
This is a fairly long title that takes up more lines
Button
Common Pitfalls
An item has a fixed width but still gets compressed by flex-shrink — remember to investigate with flex-shrink: 0 or min-width: 0.
The default of align-items is stretch; if an item's height is "mysteriously" stretched, first check whether it was set explicitly.
Text or image items that refuse to wrap and overflow usually happen because a flex item's default minimum size is its content size; set min-width: 0 or handle it with overflow.