Flexbox arranges items along one direction — a row or a column. Almost all the confusion around it comes from one idea, so learn that first and the properties stop being guesswork.
.row {
display: flex;
gap: 16px;
}Two lines, and the children sit in a row with space between them.
The one idea: two axes#
When you write display: flex, the container gets two axes:
- The main axis runs in the direction items flow. By default that is left to right.
- The cross axis runs at ninety degrees to it. By default, top to bottom.
Now the two properties people mix up become obvious:
justify-contentpositions items along the main axisalign-itemspositions them across the cross axis
With the default row direction, that means horizontal and vertical respectively. Set flex-direction: column and they swap — justify-content now moves things vertically.
Container properties#
.container {
display: flex;
flex-direction: row; /* row | row-reverse | column | column-reverse */
flex-wrap: wrap; /* nowrap (default) | wrap */
gap: 16px; /* space between items */
justify-content: flex-start; /* along the main axis */
align-items: stretch; /* across the cross axis */
align-content: flex-start; /* spacing of wrapped LINES */
}justify-content#
| Value | Result |
|---|---|
flex-start |
Packed at the start (default) |
flex-end |
Packed at the end |
center |
Packed in the middle |
space-between |
First and last at the edges, gaps equal |
space-around |
Equal space around each item |
space-evenly |
Every gap identical, including the ends |
align-items#
| Value | Result |
|---|---|
stretch |
Fill the cross axis (default) — why cards match height |
flex-start |
Top of the row |
center |
Middle |
baseline |
Text baselines line up |
stretch being the default is worth knowing — it is why a row of cards with different amounts of text still ends up the same height, which usually looks right and occasionally is not what you wanted.
Item properties#
.item {
flex-grow: 0; /* share of leftover space to take */
flex-shrink: 1; /* how willingly it shrinks */
flex-basis: auto; /* starting size before grow/shrink */
flex: 1; /* shorthand: grow 1, shrink 1, basis 0 */
align-self: center; /* override align-items for this one item */
order: 2; /* move it without changing the HTML */
}flex: 1 is the one you will write most. It means “take an equal share of the available space”. Put it on two items and they split the row in half regardless of their content.
.sidebar { flex: 0 0 240px; } /* fixed 240px, never grows or shrinks */
.content { flex: 1; } /* takes everything else */The four layouts you will actually build#
1. A navigation bar#
.nav {
display: flex;
align-items: center;
gap: 24px;
}
.nav__logo { margin-right: auto; } /* pushes everything else right */margin-right: auto on one item is the neatest trick in flexbox — it absorbs all the leftover space, so you get “logo left, links right” without wrappers.
2. Perfect centring#
.centre {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}Three lines for something that used to take genuine effort.
3. A row of cards that wraps#
.cards {
display: flex;
flex-wrap: wrap;
gap: 20px;
}
.card {
flex: 1 1 260px; /* at least 260px, share what is left, wrap when tight */
}No media queries needed. When there is not room for another 260px card, it moves to the next line.
4. A footer pushed to the bottom#
body {
display: flex;
flex-direction: column;
min-height: 100vh;
}
main { flex: 1; } /* absorbs the leftover height */The footer sits at the bottom on a short page and below the content on a long one.
The min-width: 0 trap#
This one costs people hours. A flex item’s automatic minimum size is its content, so a long unbroken string or a wide code block pushes the whole layout past the viewport:
.item {
min-width: 0; /* now it can shrink, and overflow can scroll */
overflow-x: auto;
}If your page scrolls sideways on a phone and you cannot see why, this is the first thing to try. See responsive design basics.
Flexbox or grid?#
A useful rule of thumb:
- Flexbox when the content decides the layout — a row of buttons, a nav bar, items that should flow and wrap naturally.
- Grid when the layout decides where content goes — a page skeleton, a gallery with aligned rows and columns.
They work together happily: a grid for the page, flexbox inside each cell. See CSS Grid explained.
Questions people ask#
Why is my flex item not shrinking?
Either flex-shrink: 0 is set, or its content has a minimum size. Add min-width: 0.
What is the difference between gap and margin?
gap applies only between items, never on the outside edges. Margins apply everywhere, so the last item gets one too and you end up removing it with :last-child.
Does flexbox work in older browsers?
Yes, universally in anything current. gap in flexbox is slightly newer than the rest but has been widely supported for years.
Should I use order to rearrange things?
Sparingly. It changes the visual order but not the DOM order, so keyboard and screen-reader users still get the original sequence. A visual order that disagrees with the reading order is an accessibility problem.
How do I make all items equal width?
flex: 1 on each gives them equal shares of the space. Add min-width: 0 if their content varies a lot.
Where to go next#
- CSS Grid explained — for two-dimensional layouts
- CSS basics explained
- Why is my CSS not working?