CSS Flexbox in Practice —
Patterns You'll Actually Use Every Day
Flexbox isn't hard — it's just poorly explained most of the time. This guide walks through the concepts that actually matter in real projects, with live demos you can interact with right here on the page.

What Flexbox Actually Solves
Before Flexbox became widely supported around 2015, laying out elements horizontally meant wrestling with float, clearfix hacks, and display: inline-block quirks. I spent years calculating pixel-perfect margins only to have them break when content length changed. If you've been in the field long enough, you know the pain.
Flexbox — formally the CSS Flexible Box Layout Module — was designed to solve one-dimensional layout. "One-dimensional" means it handles alignment along a single axis at a time: either a row or a column. That sounds simple, and it is. The key insight is that Flexbox lets the parent container dictate how its children are sized and spaced, rather than making each child figure it out on its own.
Container and Items — the Two Roles
Every Flexbox layout has two participants: the flex container (the parent) and the flex items (its direct children). The moment you write display: flex on a parent element, all its direct children become flex items automatically — no extra class names needed.
<div class="container">
<div class="item">A</div>
<div class="item">B</div>
<div class="item">C</div>
</div>
.container {
display: flex;
}
That's it. Three children, side by side, no floats, no clearfix, no margin calculations. The simplicity is the whole point.
Main Axis and Cross Axis — the Mental Model That Unlocks Everything
The single most important concept in Flexbox is understanding the two axes. By default, the main axis runs horizontally (left to right), and the cross axis runs vertically (top to bottom). justify-content always controls alignment along the main axis, while align-items controls alignment along the cross axis.
Here's where people get tripped up: when you switch to flex-direction: column, the axes swap. Suddenly justify-content controls vertical alignment, and align-items controls horizontal alignment. The property names don't change — the axis does.
/* Default: horizontal main axis */
.row {
display: flex;
flex-direction: row;
}
/* Vertical main axis */
.column {
display: flex;
flex-direction: column;
}
flex-direction: row
flex-direction: column
The Holy Grail: Perfect Centering in Three Lines
For years, vertically centering an element in CSS was a running joke in the community. We used position: absolute with negative margins, table-cell hacks, and all sorts of creative workarounds. With Flexbox, it takes exactly three lines.
.center-box {
display: flex;
justify-content: center; /* main axis (horizontal) */
align-items: center; /* cross axis (vertical) */
}
justify-content — Distributing Space Along the Main Axis
justify-content is the property you'll reach for most often. It determines how flex items are distributed along the main axis, and the difference between its values becomes immediately obvious when you see them side by side.
.container {
display: flex;
justify-content: flex-start; /* packed to the start (default) */
justify-content: center; /* centered */
justify-content: flex-end; /* packed to the end */
justify-content: space-between; /* first and last flush to edges */
justify-content: space-around; /* equal space around each item */
justify-content: space-evenly; /* truly equal gaps everywhere */
}
In my experience, space-between is the most frequently used value in production code. Navbars with a logo on the left and links on the right, card footers with a date on one side and a button on the other, pricing rows with the label and the price — it all comes down to space-between.
flex-wrap and Responsive Card Grids
By default, flex items try to squeeze into a single line — that's because flex-wrap defaults to nowrap. For card layouts and any scenario where items should flow onto the next line, you need flex-wrap: wrap.
.card-grid {
display: flex;
gap: 16px;
/* no flex-wrap — items shrink to fit */
}
.card-grid {
display: flex;
flex-wrap: wrap;
gap: 16px;
}
.card {
flex: 1 1 280px; /* grow, shrink, min 280px */
}
The magic is in flex: 1 1 280px. It tells each card: "You can grow, you can shrink, but start from 280px." When the row can't fit another 280px card, it wraps naturally. This gives you a responsive grid with zero media queries — it's one of my favorite Flexbox patterns.
Try resizing the browser — cards wrap naturally
The Classic Navbar Pattern
One of the places Flexbox shines brightest is navigation bars. The classic logo-on-the-left, links-on-the-right pattern used to require floats and a clearfix. Now it's a single space-between declaration.
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 24px;
height: 64px;
}
.nav-links {
display: flex;
gap: 24px;
list-style: none;
}
Understanding flex-grow, flex-shrink, and flex-basis
These three properties — often written as the flex shorthand — are where Flexbox gets its real power, and where most confusion lives. Let's break them down clearly.
flex-grow controls how much extra space an item absorbs. flex-shrink controls how much an item gives up when space is tight. flex-basis sets the starting size before growing or shrinking happens. When you write flex: 1, you're actually saying flex: 1 1 0% — grow equally, shrink equally, start from zero.
/* flex: [grow] [shrink] [basis] */
.item { flex: 0 1 auto; } /* default: don't grow, can shrink, natural size */
.item { flex: 1; } /* = 1 1 0% — absorb extra space equally */
.item { flex: none; } /* = 0 0 auto — rigid, won't budge */
.item { flex: 1 1 200px; } /* start at 200px, then flex */
The Sidebar + Main Content Pattern
One of the most practical applications of flex-grow is the sidebar layout. Give the sidebar flex: none with a fixed width, and give the main area flex: 1. The main content fills whatever space is left — no calculations needed.
Takeaways
- Flexbox handles one-dimensional layout by letting the parent container control how children are sized, spaced, and aligned — replacing the old float-and-clearfix approach entirely.
- Understanding main axis vs. cross axis is the key: justify-content always works along the main axis, align-items along the cross axis, regardless of flex-direction.
- Perfect vertical and horizontal centering takes exactly three CSS properties: display: flex, justify-content: center, and align-items: center.
- Combine flex-wrap: wrap with flex: 1 1 [min-width] on children to create responsive card grids without a single media query.
- The flex shorthand (grow, shrink, basis) is the heart of flexible sizing — learn the difference between flex: 1, flex: auto, and flex: none.
- Use align-self and order for per-item overrides, but be mindful of accessibility — visual order should generally match DOM order for screen readers and keyboard navigation.