I'll be honest. I've been writing CSS professionally for years and I still pause when I need to vertically center something with Flexbox. Not because the syntax is hard -- align-items: center -- but because I can never remember whether align-items is the cross axis or the main axis, and which axis is which depends on the flex direction. The mental model has a learning curve that the simplicity of the syntax hides.
So here's the reference I wish I'd had when I started. Not the spec. Not the comprehensive guide. Just the parts that solve actual layout problems.
The two axes
Everything in Flexbox revolves around two axes:
-
Main axis: the direction items flow. Set by
flex-direction. - Cross axis: perpendicular to the main axis.
/* Main axis: horizontal (left to right) */
flex-direction: row;
/* Main axis: vertical (top to bottom) */
flex-direction: column;
Once you know which axis is which, the property names make sense:
-
justify-contentaligns items along the main axis -
align-itemsaligns items along the cross axis
When flex-direction is row (the default), justify-content is horizontal and align-items is vertical. When flex-direction is column, they swap. This swap is the source of nearly all Flexbox confusion.
The centering patterns
Centering is Flexbox's most famous use case. Here are the three patterns:
/* Center horizontally (row direction) */
.container {
display: flex;
justify-content: center;
}
/* Center vertically (row direction) */
.container {
display: flex;
align-items: center;
}
/* Center both */
.container {
display: flex;
justify-content: center;
align-items: center;
}
For the "center both" case, there's a shorter alternative using Grid (display: grid; place-items: center), but Flexbox is the standard approach.
Space distribution
justify-content has several values for distributing space between items:
/* Items packed to the start */
justify-content: flex-start;
/* Items packed to the end */
justify-content: flex-end;
/* Items centered, no space at edges */
justify-content: center;
/* Equal space between items, none at edges */
justify-content: space-between;
/* Equal space around items (half-size at edges) */
justify-content: space-around;
/* Equal space everywhere including edges */
justify-content: space-evenly;
In practice, space-between is the one I use most. It's the pattern for a navbar where the logo is on the left and the menu is on the right:
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
}
Two children, one pushed to each side, vertically centered. This replaces the old float: left / float: right pattern entirely.
The flex shorthand
The flex property on child items is shorthand for three values:
flex: <flex-grow> <flex-shrink> <flex-basis>;
- flex-grow: how much the item should grow relative to siblings when there's extra space. 0 means don't grow.
- flex-shrink: how much the item should shrink when there's not enough space. 1 means shrink proportionally.
- flex-basis: the initial size before growing or shrinking. Like a starting width (or height in column direction).
The values that matter:
/* Don't grow, don't shrink, use auto width */
flex: 0 0 auto; /* same as flex: none */
/* Grow to fill space, shrink if needed, start from 0 */
flex: 1 1 0; /* same as flex: 1 */
/* Grow to fill space, start from auto width */
flex: 1 1 auto; /* same as flex: auto */
flex: 1 on all children makes them share space equally. flex: none on an element makes it rigid -- it won't grow or shrink.
The classic sidebar layout:
.layout {
display: flex;
}
.sidebar {
flex: 0 0 250px; /* fixed 250px width */
}
.main {
flex: 1; /* takes remaining space */
}
The gap property
Before gap existed in Flexbox, spacing items required margins with a negative margin hack on the container, or using :last-child selectors to remove the trailing margin. gap solved this cleanly:
.container {
display: flex;
gap: 16px;
}
This puts 16px between every item but not before the first or after the last. You can also set row and column gaps separately with row-gap and column-gap, though this mainly matters when items wrap.
Wrapping
By default, flex items try to fit on one line. flex-wrap: wrap allows them to flow to the next line:
.tag-list {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
When items wrap, align-content controls how the wrapped lines are distributed along the cross axis. It accepts the same values as justify-content (center, space-between, etc.). align-items still controls alignment within each line; align-content controls the lines themselves.
This distinction between align-items and align-content is another common source of confusion. If you're not wrapping, align-content has no effect.
Order and visual reordering
The order property changes the visual order of items without changing the DOM order:
.item-first {
order: -1; /* moves to the beginning */
}
.item-last {
order: 99; /* moves to the end */
}
This is useful for responsive layouts where the visual order should differ on mobile vs desktop. But use it sparingly -- screen readers follow the DOM order, not the visual order. If the order matters for understanding the content, change the DOM instead.
Five common Flexbox mistakes
Using
align-items: stretchwithout realizing it's the default. If your flex items are unexpectedly stretching to fill the container's height, that'salign-items: stretchin action. Set it toflex-startif you want items at their natural height.Forgetting
min-width: 0for truncated text. By default, flex items won't shrink below their content's minimum size. If you have a long text string withtext-overflow: ellipsis, it won't truncate because the flex item refuses to shrink past the text length. Addingmin-width: 0to the flex item overrides this.Using
flex-direction: columnand wondering whyjustify-content: centerdoesn't center horizontally. It doesn't because in column direction,justify-contentis vertical. Usealign-items: centerfor horizontal centering in column direction.Nesting flex containers unnecessarily. Not every child layout needs its own
display: flex. Sometimes a child just needsmargin-left: autoto push itself to the end of the main axis.Not using
flex-shrink: 0on fixed-width elements. If you want a sidebar to stay at exactly 250px, you needflex: 0 0 250px. Withoutflex-shrink: 0, the sidebar can shrink below 250px on narrow viewports.
For building Flexbox layouts visually and seeing how each property affects the result, I put together a Flexbox generator at zovo.one/free-tools/flexbox-generator that lets you toggle properties and copy the CSS.
Flexbox has been stable for years now, and it remains the right tool for one-dimensional layout. Master the two axes, understand the flex shorthand, use gap for spacing, and you've got 90% of what you need. The rest is reference material you look up when you need it.
I'm Michael Lip. I build free developer tools at zovo.one. 350+ tools, all private, all free.
Top comments (0)