CSS Flexbox: A Practical Guide for Real Layouts (2026)

Flexbox is a CSS layout mode for arranging items along one axis, either a row or a column. Set display flex on the container, pick a direction with flex-direction, then use justify-content for the main axis and align-items for the cross axis.
Part of the complete web design guide.
On this page
- The one-dimensional idea
- justify-content vs align-items
- The flex shorthand, decoded
- A common gotcha: flex items and min-width
- Wrapping and gap
- Where Flexbox beats Grid (and vice versa)
- Centering: the thing everyone googles
- Accessibility and order
- Should you still learn it in 2026?
- FAQ
- Is Flexbox still relevant now that CSS Grid exists?
- What’s the difference between flex: 1 and flex: 1 1 auto?
- Why is my flex item overflowing its container?
Flexbox has been in every browser for over a decade now, and it’s still the layout tool I reach for most often. Not because it’s trendy, but because most of what I build is one-dimensional: a row of cards, a nav bar, a form, a footer. If you’ve ever fought with floats or wondered why your columns won’t line up, this is the thing that fixes it.
I’ve been writing CSS professionally for years, and I still see the same handful of misunderstandings trip people up. So here’s what Flexbox actually does, how the properties behave, and the patterns that hold up on real projects.
The one-dimensional idea
Grid handles rows and columns at the same time. Flexbox handles a single axis at a time: either a row or a column. That’s the whole mental model. You pick a direction with flex-direction, and then you distribute space and align items along that line.
.nav {
display: flex;
flex-direction: row; /* default */
justify-content: space-between;
align-items: center;
gap: 1rem;
}
display: flex turns an element into a flex container, and its direct children become flex items. Only direct children. That trips people up constantly when they wonder why a deeply nested element isn’t responding to their flex rules.
justify-content vs align-items
This is the pair that confuses everyone, and it’s actually simple once you remember the axis. justify-content works along the main axis (the direction you set). align-items works along the cross axis (perpendicular to it).
- Row direction:
justify-contentmoves things left/right,align-itemsmoves them up/down. - Column direction: it flips.
justify-contentnow moves things up/down.
Common values for justify-content: flex-start, center, flex-end, space-between, space-around, space-evenly. For align-items: stretch (the default), flex-start, center, flex-end, baseline.
If you only remember one thing: main axis gets justify, cross axis gets align.
The flex shorthand, decoded
Most real-world Flexbox confusion lives in flex-grow, flex-shrink, and flex-basis. The flex shorthand sets all three in order: grow, shrink, basis.
.item { flex: 1; } /* 1 1 0% - share space equally */
.sidebar { flex: 0 0 260px; } /* fixed width, never grow or shrink */
.content { flex: 1 1 auto; } /* grow and shrink from content size */
flex: 1 is the one you’ll use most. It means “grow to fill available space, shrink if needed, and start from zero.” That last part matters: a basis of 0% means items split space evenly regardless of their content, which is usually what you want for equal-width columns.
Compare that to flex: 1 1 auto, where the starting size is the content’s natural size. Two items with different content lengths will end up different widths even with the same grow value. If you’ve ever expected equal columns and gotten uneven ones, that’s almost always the reason.
A common gotcha: flex items and min-width
Flex items have an implicit min-width: auto, which means they refuse to shrink below their content’s minimum size. Long words, URLs, or a wide <pre> block will blow out your layout. The fix:
.content {
flex: 1;
min-width: 0; /* allow shrinking below content size */
}
I’ve fixed more “why is my layout overflowing on mobile” bugs with min-width: 0 than almost anything else. Same idea applies to min-height: 0 for column layouts that scroll.
Wrapping and gap
By default flex items stay on one line and shrink to fit. Add flex-wrap: wrap and they’ll flow onto new lines instead. This is how you build a responsive card grid without media queries:
.cards {
display: flex;
flex-wrap: wrap;
gap: 1.5rem;
}
.cards > .card {
flex: 1 1 280px; /* at least ~280px, grow to fill */
max-width: 100%;
}
The flex-basis of 280px acts like a soft minimum. Each card wants to be at least 280px wide, and when the container can’t fit another one, it wraps. No breakpoints needed.
One note on gap: it works in Flexbox now, in every current browser. You no longer need the old negative-margin tricks that were standard practice years ago. If you’re maintaining older code, that’s worth remembering when you clean things up.
Where Flexbox beats Grid (and vice versa)
People love to frame this as a competition. It isn’t. They solve different problems.
- Use Flexbox for nav bars, button groups, form rows, card contents, toolbars, centering a single element, and any layout where the content determines the size.
- Use Grid for full page layouts, dashboards, and anything where you’re defining a structure and the content slots into it.
In practice you’ll use both on the same page. A Grid handles the overall page regions, and Flexbox handles the small stuff inside each region. That’s a normal, healthy combination, not a sign you did something wrong.
Centering: the thing everyone googles
For years, “how do I center a div” was a running joke. Flexbox made it a two-line answer:
.center {
display: flex;
justify-content: center;
align-items: center;
min-height: 100dvh; /* dvh handles mobile browser chrome */
}
Note the dvh instead of vh. On mobile, 100vh includes the browser’s address bar, which causes a jump when it hides. dvh (dynamic viewport height) accounts for that and is well supported in 2026. If you’re still using 100vh for full-screen sections and wondering why mobile looks off, this is your fix.
Accessibility and order
Flexbox lets you reorder items visually with the order property, and it’s tempting to use it to rearrange content. Be careful. Visual order and DOM order diverge, which breaks keyboard tab order and screen readers. If someone tabs through your nav and the focus jumps around unpredictably, that’s a real problem, not a nitpick.
Use order for small cosmetic tweaks, not for restructuring a page. If the source order is wrong, fix the source order.
Should you still learn it in 2026?
Yes, absolutely. Grid didn’t replace Flexbox, and neither did any of the newer layout features. Flexbox is stable, universally supported, and the right tool for a huge amount of everyday work. The syntax hasn’t changed in years, which is a good thing. What’s changed is that the old workarounds (clearfixes, negative margins, float-based grids) are finally safe to delete.
If you’re maintaining a site that still leans on those old techniques, it’s usually worth cleaning up. I do a lot of that kind of work through my Long Island web design projects, and modernizing a float-based layout into Flexbox and Grid is one of the more satisfying jobs because it makes everything downstream easier to change.
FAQ
Is Flexbox still relevant now that CSS Grid exists?
Completely. Grid is for two-dimensional layouts, Flexbox is for one-dimensional ones. Most real pages use both. Flexbox is also better when the content should determine the sizing rather than a predefined grid.
What’s the difference between flex: 1 and flex: 1 1 auto?
flex: 1 uses a basis of 0%, so items split space evenly no matter their content. flex: 1 1 auto starts from the content’s natural size, so items with more content end up wider. Use the first for equal columns, the second when content should influence width.
Why is my flex item overflowing its container?
Almost always the implicit min-width: auto. Add min-width: 0 to the flex item (or min-height: 0 for columns) and it’ll shrink as expected. Long unbroken strings and wide code blocks are the usual culprits.


