Flexbox
Table of Contents
- The Layout Problem
- Flex Container and Flex Items
- The Main Axis and the Cross Axis
- Spacing and Alignment
- gap
- Wrapping
- Sizing Items: grow, shrink, basis
- Recipe: A Navbar
- Recipe: Centering and Cards
- Try It Yourself
1. The Layout Problem
So far, every element has stacked from top to bottom, because that's how block elements flow. Real pages need more: a logo on the left and a menu on the right, three cards in a row, a button centered in a box.
For years this was done with awkward tricks — floats, tables, fixed widths. Flexbox ("flexible box") is the modern tool built for the job. It's designed to lay items out along one line — a row or a column — and to distribute the space between them.
2. Flex Container and Flex Items
Flexbox starts with one declaration on a parent:
<div class="row">
<div>One</div>
<div>Two</div>
<div>Three</div>
</div>
.row {
display: flex;
}
The parent becomes a flex container, and its direct children
become flex items. Immediately, the three divs sit side by side
instead of stacking. Only the direct children are affected; grandchildren
aren't.
Some properties go on the container (how to arrange the items), and some on the items (how each one behaves). Knowing which is which is half the battle.
3. The Main Axis and the Cross Axis
Flexbox thinks in two directions:
flex-direction: row (default)
main axis ───────────────────────────►
┌─────┐ ┌─────┐ ┌─────┐
│ 1 │ │ 2 │ │ 3 │ cross axis
└─────┘ └─────┘ └─────┘ │
▼
flex-direction: column
main axis │ ┌─────┐
│ │ 1 │
│ └─────┘ cross axis
│ ┌─────┐ ─────────────►
▼ │ 2 │
└─────┘
- The main axis runs in the direction items are laid out.
- The cross axis is perpendicular to it.
flex-direction chooses the main axis: row (the default, left to
right), column (top to bottom), or the reversed versions
row-reverse and column-reverse. Everything in the next section
refers to main and cross, not to horizontal or vertical — so the same
property works in either direction.
Reversing changes only the visual order, not the order for screen readers or keyboard users. That can confuse them, so use it sparingly.
4. Spacing and Alignment
Two container properties do most of the work:
| Property | Axis | Controls |
|---|---|---|
justify-content | Main | How items are spread along the line |
align-items | Cross | How items line up across the line |
justify-content values:
| Value | Result |
|---|---|
flex-start | Items packed at the start (default) |
flex-end | Packed at the end |
center | Packed in the middle |
space-between | First and last at the edges, equal space between |
space-around | Equal space around each item |
space-evenly | Exactly equal space everywhere |
align-items values: stretch (default: items fill the cross
size), flex-start, flex-end, center, and baseline (text
baselines line up).
.row {
display: flex;
justify-content: space-between;
align-items: center;
}
A mental shortcut: "justify" is along the main axis, "align" is across
it. If you're unsure, try both and look at DevTools — in the Elements
panel, a small flex badge next to the element toggles an overlay that
draws the axes and free space.
5. gap
To put space between items, use gap on the container instead of
margins on each child:
.row {
display: flex;
gap: 1rem;
}
gap adds space only between items, never on the outside edges, so
there is no leftover margin on the last item to fight with. You can
give two values: gap: 1rem 2rem is row gap then column gap.
6. Wrapping
By default, a flex container keeps everything on one line, shrinking items to fit — even until they overflow. To let items flow onto a new line, turn on wrapping:
.row {
display: flex;
flex-wrap: wrap;
gap: 1rem;
}
Items now keep their size and wrap onto the next row when there isn't
room. This is the basis of many "responsive without media queries"
layouts. The shorthand flex-flow: row wrap sets direction and wrap
together.
7. Sizing Items: grow, shrink, basis
Properties on the items control how they share the container's free space:
| Property | Meaning |
|---|---|
flex-basis | The item's starting size on the main axis, before sharing |
flex-grow | How much of the leftover space it gets (0 = none) |
flex-shrink | How much it gives up when there isn't enough space |
The shorthand is flex: grow shrink basis. The values you'll use most:
.item { flex: 1; } /* share the free space equally */
.sidebar { flex: 0 0 16rem; } /* fixed 16rem, never grows or shrinks */
.content { flex: 1; } /* take everything that's left */
flex: 1 on every item gives you equal-width columns. If one item has
flex: 2 and the other two flex: 1, the big one gets double the
share.
margin: auto is a handy trick: on a flex item, margin-left: auto
pushes it all the way to the right, absorbing all the free space.
8. Recipe: A Navbar
Here's a header with the name on the left and the links on the right:
<header class="site-header">
<a href="index.html" class="brand">Dara Sok</a>
<nav aria-label="Main">
<ul class="nav-list">
<li><a href="index.html">Home</a></li>
<li><a href="about.html">About</a></li>
<li><a href="#contact">Contact</a></li>
</ul>
</nav>
</header>
.site-header {
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 1rem;
}
.nav-list {
display: flex;
gap: 1.5rem;
list-style: none;
margin: 0;
padding: 0;
}
Two flex containers are used: the header spreads the brand and the nav
apart, and .nav-list lays the <li>s in a row. Nesting flex
containers like this is normal — each handles one line of the design.
9. Recipe: Centering and Cards
Centering. Vertically centering something was once famously hard. With Flexbox, it's three lines:
.centered {
display: flex;
justify-content: center;
align-items: center;
min-height: 50vh;
}
A row of cards that share space, wrap when needed, and have matching widths:
.projects {
display: flex;
flex-wrap: wrap;
gap: 1rem;
}
.projects .card {
flex: 1 1 14rem;
}
flex: 1 1 14rem reads: "start at 14rem, grow to fill spare space, and
shrink if you must." On a wide screen you might get three cards in a
row. On a narrow one they wrap to two, then one, with no media query.
A caveat: in a wrapping flex layout, each row shares space on its own, so the last row's cards can end up stretched wider than the others. Chapter 10's Grid doesn't have this problem, which is one reason it's better for card galleries.
10. Try It Yourself
- See the axes. Make a
.rowwith three boxes and turn on Flexbox. Changeflex-directiontocolumn, then play withjustify-contentandalign-items. Use the DevTools flex overlay. - Build the navbar. Use the recipe in section 8 on both pages.
Check that the links are reachable with
Tab. - Make a sticky footer. Give
bodydisplay: flex,flex-direction: column, andmin-height: 100vh, thenmainflex: 1. Now the footer sits at the bottom even on short pages. - Lay out the projects. Make your project
<article>s flex withflex: 1 1 14rem. Resize the window and watch them wrap. Add a fourth card and see what the last row does. - Push with margin. In a navbar, add a "Sign in" link and give it
margin-left: auto. Where does it go? - Reorder carefully. Use
flex-direction: row-reverseon the nav, thenTabthrough it. What do you notice about the order?
Next, Grid: the other half of modern layout, built for rows and columns at the same time.
Buy Me a Coffee
Found this tutorial helpful? Consider buying me a coffee to support more free content!