Introduction
For years, centering a <div> was a running joke among web developers. Floats, tables, absolute positioning — every method had ugly edge cases. Then Flexbox arrived and made layout sane.
Flexbox (the Flexible Box Layout) is a CSS tool for arranging elements in a single direction — a row or a column — and controlling how they align, space out, and resize. Once it clicks, you'll reach for it every single day.
This guide assumes zero Flexbox knowledge. By the end you'll understand the model, know every important property, and have copy-paste layouts for the things you actually build.
The One Idea That Makes Flexbox Click
Flexbox has exactly two roles:
| Role | What it is |
|---|---|
| Flex container | The parent — you set display: flex on it |
| Flex items | The direct children — they get arranged automatically |
<div class="container"> <!-- flex container -->
<div class="item">1</div> <!-- flex item -->
<div class="item">2</div> <!-- flex item -->
<div class="item">3</div> <!-- flex item -->
</div>
.container {
display: flex; /* that's it — children are now flex items */
}
The moment you write display: flex, the children line up in a row. Everything else is just fine-tuning.
The Two Axes (Important)
Flexbox works along two axes, and almost every property targets one of them:
- Main axis → the direction items flow (horizontal by default)
- Cross axis → perpendicular to it (vertical by default)
flex-direction: row (default)
main axis ───────────────►
┌─────┐ ┌─────┐ ┌─────┐
│ 1 │ │ 2 │ │ 3 │ │ cross axis
└─────┘ └─────┘ └─────┘ ▼
Remember this: justify-content controls the MAIN axis, align-items controls the CROSS axis. Mixing these two up is the #1 beginner confusion.
Container Properties
These go on the parent (.container).
display: flex
Turns on Flexbox. Use inline-flex if you want the container itself to behave like an inline element.
flex-direction
Sets the main axis — which way items flow.
.container { flex-direction: row; } /* default: left → right */
.container { flex-direction: column; } /* top → bottom */
.container { flex-direction: row-reverse; } /* right → left */
.container { flex-direction: column-reverse; } /* bottom → top */
justify-content (main axis)
Distributes items along the main axis.
.container { justify-content: flex-start; } /* default: packed to start */
.container { justify-content: center; } /* centered */
.container { justify-content: flex-end; } /* packed to end */
.container { justify-content: space-between; } /* edges, even gaps between */
.container { justify-content: space-around; } /* even space around each */
.container { justify-content: space-evenly; } /* perfectly equal gaps */
| Value | Use it for |
|---|---|
center |
Centering a row of items horizontally |
space-between |
Navbar: logo left, links right |
space-evenly |
Equal spacing in a button group |
align-items (cross axis)
Aligns items along the cross axis.
.container { align-items: stretch; } /* default: fill container height */
.container { align-items: center; } /* vertically centered */
.container { align-items: flex-start; } /* top */
.container { align-items: flex-end; } /* bottom */
.container { align-items: baseline; } /* align text baselines */
gap
The cleanest way to add space between items — no more margin hacks.
.container {
display: flex;
gap: 1rem; /* space between all items */
/* gap: 1rem 2rem; row-gap column-gap */
}
flex-wrap
By default items squeeze onto one line. wrap lets them flow to the next line.
.container { flex-wrap: nowrap; } /* default: one line, items shrink */
.container { flex-wrap: wrap; } /* items wrap to new lines */
Item Properties
These go on the children (.item).
flex-grow, flex-shrink, flex-basis
These control how items resize. Most of the time you'll use the flex shorthand instead:
.item { flex: 1; } /* grow to fill equal space */
.item { flex: 2; } /* take twice as much space as flex: 1 items */
.item { flex: 0 0 200px; } /* don't grow, don't shrink, stay 200px wide */
| Shorthand | Meaning |
|---|---|
flex: 1 |
Item grows to share leftover space equally |
flex: 0 0 auto |
Fixed size, never grows or shrinks |
flex: 0 0 200px |
Locked to 200px |
align-self
Override align-items for a single item.
.item { align-self: flex-end; } /* this one item drops to the bottom */
order
Change visual order without touching the HTML.
.item { order: 2; } /* higher number = appears later. Default is 0 */
The Famous "Center a Div"
The thing Flexbox is most loved for — perfect centering, both axes, in 3 lines:
.container {
display: flex;
justify-content: center; /* horizontal */
align-items: center; /* vertical */
min-height: 100vh; /* full screen height */
}
<div class="container">
<div>I am perfectly centered 🎯</div>
</div>
That's it. The decade-long struggle, solved.
Real Layout #1 — Navbar
Logo on the left, links on the right:
.navbar {
display: flex;
justify-content: space-between; /* push logo and links apart */
align-items: center; /* vertically center everything */
padding: 1rem 2rem;
}
.nav-links {
display: flex;
gap: 1.5rem; /* space between links */
}
<nav class="navbar">
<div class="logo">MySite</div>
<div class="nav-links">
<a href="#">Home</a>
<a href="#">Blog</a>
<a href="#">Contact</a>
</div>
</nav>
Real Layout #2 — Responsive Card Row
Cards that sit in a row and wrap on small screens:
.card-row {
display: flex;
flex-wrap: wrap; /* wrap on small screens */
gap: 1.5rem;
}
.card {
flex: 1 1 250px; /* grow, shrink, min width 250px */
}
Each card is at least 250px wide, grows to fill the row, and wraps to the next line when there's no room. Fully responsive with no media queries.
Real Layout #3 — Sticky Footer (Holy Grail)
Footer stays at the bottom even when content is short:
body {
display: flex;
flex-direction: column;
min-height: 100vh;
}
main {
flex: 1; /* main content grows to fill, pushing footer down */
}
Common Mistakes Beginners Make
| Mistake | Fix |
|---|---|
Setting justify-content to center vertically |
That's align-items — justify-content is the main axis |
Forgetting display: flex on the parent |
Item properties do nothing without it |
| Using margins for spacing | Use gap instead — much cleaner |
Expecting align-items to work with one item filling height |
It works; check the container has a defined height |
| Confusing it with Grid | Flexbox = 1 direction (row OR column). Grid = 2D (rows AND columns) |
Flexbox vs CSS Grid
A quick rule of thumb:
| Use Flexbox when… | Use Grid when… |
|---|---|
| Laying out items in one direction | Laying out a 2D layout (rows + columns) |
| Navbars, button groups, card rows | Page layouts, dashboards, image galleries |
| You want content to dictate size | You want a strict grid structure |
They work great together — Grid for the page skeleton, Flexbox for the components inside it.
Flexbox Cheat Sheet
CONTAINER (parent)
display: flex → turn it on
flex-direction: row|column
justify-content: ... → MAIN axis alignment
align-items: ... → CROSS axis alignment
gap: 1rem → space between items
flex-wrap: wrap → allow multiple lines
ITEM (child)
flex: 1 → grow to fill space
flex: 0 0 200px → fixed 200px
align-self: ... → override alignment for one item
order: 2 → change visual order
Final Thought
Flexbox feels confusing for about a day, then becomes second nature. The trick is to always ask two questions: "Which way are my items flowing?" (main axis) and "How do I align them across?" (cross axis). Answer those and the right property is obvious.
Open your editor, paste the centering snippet, and start tweaking values. Nothing teaches Flexbox faster than watching boxes move in real time. Once it clicks, you'll never fight CSS layout the same way again.