A Complete Guide to Flexbox: Every Property, Explained

Flexbox in one sentence
Flexbox is a one-dimensional CSS layout system that distributes space and aligns items along a single axis. You set display: flex on a container, and its direct children become flex items that line up in a row (or column) and can grow, shrink, and align to fill the available space. That is the whole idea: a parent that lays out its children along one axis, with fine-grained control over spacing and alignment.
Everything else in Flexbox is just properties that adjust how that distribution and alignment behave. This guide walks through every one of them, grouped by whether it lives on the container or on the items, with copy-pasteable code and the mental model that makes each property click.
.container {
display: flex;
}
That single declaration turns children into flex items. Below we make it do real work.
The two axes: main and cross
Flexbox has no fixed "horizontal" and "vertical." Instead it has a main axis and a cross axis, and which direction they point depends on flex-direction.
- The main axis runs in the direction items flow. With the default
flex-direction: row, it runs left to right. - The cross axis runs perpendicular to it. With a row, the cross axis runs top to bottom.
This matters because the alignment properties are named after axes, not directions. justify-content always works along the main axis; align-items always works along the cross axis. Switch flex-direction to column and their real-world effect swaps, because the axes rotated. Once you internalize main-vs-cross, the property names stop feeling arbitrary.
| Concept | Default (row) direction |
With flex-direction: column |
|---|---|---|
| Main axis | Left → right | Top → bottom |
| Cross axis | Top → bottom | Left → right |
justify-content controls |
Horizontal spacing | Vertical spacing |
align-items controls |
Vertical alignment | Horizontal alignment |
Container properties
These go on the element with display: flex. They govern how the whole group behaves.
flex-direction
Sets the main axis and the order items flow in.
.container {
display: flex;
flex-direction: row; /* row | row-reverse | column | column-reverse */
}
row(default): items left to right.column: items top to bottom — the single most common reason people reach for a column is stacking cards or form fields.row-reverse/column-reverse: same axis, reversed order. Note this is a visual reversal only; it does not change DOM or tab order, so avoid it where reading order matters for accessibility.
flex-wrap
By default flex items refuse to wrap — they shrink to fit on one line instead. flex-wrap changes that.
.container {
display: flex;
flex-wrap: wrap; /* nowrap (default) | wrap | wrap-reverse */
}
Set wrap and items that no longer fit drop to a new line. This is the foundation of a simple responsive grid: give each item a flex-basis and let wrapping handle the rest, no media queries required. The shorthand flex-flow: row wrap combines flex-direction and flex-wrap in one line.
justify-content
Distributes leftover space along the main axis.
.container {
display: flex;
justify-content: space-between;
}
| Value | What it does |
|---|---|
flex-start |
Items packed to the start (default) |
flex-end |
Items packed to the end |
center |
Items centered as a group |
space-between |
First and last item touch the edges; equal gaps between |
space-around |
Equal space around each item (edges get half-gaps) |
space-evenly |
Truly equal gaps, including at the edges |
space-between is the workhorse for navbars: logo hard left, links hard right, one line of CSS.
align-items
Aligns items along the cross axis — for a row, that is vertical alignment.
.container {
display: flex;
align-items: center;
}
stretch(default): items stretch to fill the container's cross size. This is why two side-by-side cards with different content end up the same height automatically.flex-start/flex-end: align to the top / bottom of a row.center: center vertically — the second half of the classic centering trick.baseline: align items by their text baselines, useful when items have different font sizes.
align-content
Only does anything when items wrap onto multiple lines. It distributes space between the lines along the cross axis, using the same value set as justify-content (flex-start, center, space-between, and so on). On a single-line flex container it has no effect, which trips up a lot of people expecting it to behave like align-items.
gap
The cleanest way to space flex items. gap adds consistent spacing between items without adding it on the outer edges.
.container {
display: flex;
gap: 1rem; /* row-gap and column-gap at once */
/* gap: 1rem 2rem; row-gap column-gap */
}
Before gap was supported in Flexbox, people used margins and negative-margin hacks. Those days are over: gap works in every current browser (Chrome, Firefox, Safari, and Edge have supported flex gap since 2021). Reach for it instead of margins on items.
Item properties
These go on the flex items — the children — and control how each one behaves within the shared space.
flex-grow
How much an item grows to absorb extra free space, relative to its siblings. It is a unitless proportion, not a size.
.item {
flex-grow: 1; /* default is 0 (do not grow) */
}
If every item has flex-grow: 1, they share leftover space equally. Give one item flex-grow: 2 and it takes twice as large a share of the extra space (not twice the total width). A single flex-grow: 1 on one child is the standard way to make it fill the remaining room — think a search input that expands while buttons stay their natural size.
flex-shrink
The mirror image: how much an item shrinks when there is not enough room.
.item {
flex-shrink: 1; /* default is 1 (allowed to shrink) */
}
Default 1 means items shrink proportionally to avoid overflow. Set flex-shrink: 0 to forbid an item from shrinking — handy for a fixed-width sidebar or an icon that must never squish.
flex-basis
The item's size along the main axis before grow and shrink are applied. It is the starting point.
.item {
flex-basis: 200px; /* auto (default) | <length> | <percentage> */
}
auto means "use my width/height or my content size." Set flex-basis: 0 together with flex-grow: 1 on several items and they become perfectly equal columns, because they all start from zero and divide space evenly.
The flex shorthand
You will almost always set these three through the flex shorthand rather than individually. Learn these values and you have covered 95% of real usage.
| Shorthand | Expands to | Meaning |
|---|---|---|
flex: 1 |
1 1 0% |
Grow and shrink from a zero basis — equal-width columns |
flex: auto |
1 1 auto |
Grow and shrink from natural size |
flex: none |
0 0 auto |
Fixed at natural size, never grow or shrink |
flex: 0 1 auto |
(the default) | Shrink but don't grow |
flex: 1 1 200px |
1 1 200px |
Start at 200px, then flex |
/* Three equal columns */
.column {
flex: 1;
}
align-self
Overrides the container's align-items for a single item. Same value set (auto, flex-start, flex-end, center, baseline, stretch). Use it when one item needs to break from the group — say, pinning a "New" badge to the top of a row of centered items.
.special {
align-self: flex-start;
}
order
Changes the visual position of an item without touching the HTML. Lower numbers come first; the default is 0, so order: -1 pulls an item to the front.
.promoted {
order: -1;
}
Use order sparingly. Like row-reverse, it changes visual order but not DOM or keyboard tab order, so heavy use creates a confusing, inaccessible experience for keyboard and screen-reader users. It shines for small, responsive rearrangements, not wholesale reordering.
Two patterns you'll use constantly
Perfect centering
The reason Flexbox first won people over. Three lines center anything, horizontally and vertically, with no magic numbers:
.center {
display: flex;
justify-content: center; /* main axis */
align-items: center; /* cross axis */
}
This works regardless of the child's size. For a deeper tour of the alternatives and their trade-offs, see our guide on how to center a div.
A responsive card row with no media queries
Combine flex-wrap, gap, and a flex-basis and the layout adapts on its own:
.cards {
display: flex;
flex-wrap: wrap;
gap: 1rem;
}
.card {
flex: 1 1 250px; /* grow, shrink, never narrower than ~250px */
}
Each card wants to be at least 250px wide. Three fit on a wide screen, two on a tablet, one on a phone — the browser recalculates as the viewport changes, and you never wrote a breakpoint. This is Flexbox at its best: intrinsically responsive.
Flexbox in Sass
If you use Sass, wrap common Flexbox patterns in a mixin so you stop repeating the same three lines everywhere:
@mixin flex-center($direction: row) {
display: flex;
flex-direction: $direction;
justify-content: center;
align-items: center;
}
.hero {
@include flex-center(column);
gap: 1rem;
}
That compiles to standard CSS but keeps your intent readable. If you are new to writing mixins, our complete guide to Sass covers the syntax and when a mixin beats a plain class.
When Flexbox is the wrong tool
Flexbox is one-dimensional: it excels at laying out items along a single row or column. When you need to control rows and columns at the same time — a true two-dimensional grid where things line up both horizontally and vertically — CSS Grid is the better fit. A common, sensible approach is Grid for the overall page skeleton and Flexbox for the components inside each region.
Read Flexbox vs CSS Grid for a decision framework, and the step-by-step CSS Grid tutorial when you're ready to build a two-dimensional layout.
Browser support and gotchas
Flexbox is universally supported — every browser in current use has shipped unprefixed Flexbox for years, so you can use it in production without fallbacks or vendor prefixes. A few things still catch people out:
align-contentneeds multiple lines. On a single-line container it does nothing; you probably wantalign-items.flex-shrinkcan crush content. If text or an image is being squished unexpectedly, setflex-shrink: 0on that item.- Percentage
flex-basisneeds a sized parent along the main axis to resolve against, or it falls back to content size. orderand*-reversedon't move focus order. They reorder pixels, not the DOM — keep that in mind for accessibility.- Minimum size defaults to content. A flex item won't shrink below its content's intrinsic minimum unless you add
min-width: 0(ormin-height: 0in a column). This is the fix for the infamous "my flex item overflows its container" bug.
Quick reference cheat sheet
| Property | Goes on | Controls |
|---|---|---|
flex-direction |
Container | Direction of the main axis |
flex-wrap |
Container | Whether items wrap to new lines |
justify-content |
Container | Spacing along the main axis |
align-items |
Container | Alignment along the cross axis |
align-content |
Container | Spacing of wrapped lines (multi-line only) |
gap |
Container | Space between items |
flex-grow |
Item | Share of extra space |
flex-shrink |
Item | How much it shrinks when cramped |
flex-basis |
Item | Starting size on the main axis |
flex |
Item | Shorthand for grow / shrink / basis |
align-self |
Item | Override cross-axis alignment for one item |
order |
Item | Visual position (not DOM order) |
Master the two axes and the container-versus-item split, and the rest of Flexbox is just picking the property that names what you want. Set display: flex, decide your direction, then reach for justify-content, align-items, and gap to place things — and the flex shorthand to decide how items share the space.