Overview
Flexbox is the one-dimensional layout primitive: a single row or column whose children grow, shrink, and align along one axis. Use it for nav bars, toolbars, button rows, and side-by-side input groups. For 2D layouts where rows and columns must align, use css-grid instead. The umbrella sits at css.
Use flex for 1D, grid for 2D
A row of buttons, a media object with avatar and text, a horizontal nav: flex. A page shell with sidebar, header, and footer: grid. The signal is whether items on different rows need to align by column. If they do, you want grid.
.toolbar {
display: flex;
gap: 0.5rem;
align-items: center;
}If you reach for flex-wrap plus manual width math to fake a 2D grid, stop. That is a grid-template-columns: repeat(auto-fill, minmax(...)) in disguise.
Name the axes: main and cross
Every flex container has a main axis (set by flex-direction) and a cross axis perpendicular to it. The property names follow:
justify-contentaligns on the main axis.align-itemsaligns each item on the cross axis.align-contentaligns wrapped lines on the cross axis (only withflex-wrap).
flex-direction: row puts the main axis horizontal; column puts it vertical, and the property meanings swap perpendicularly. If your align-items: center stops working when you flip direction, the axis flipped under you.
Use gap instead of margins
Flex supports gap in every evergreen browser since 2021. Use it.
/* Wrong: margins that leak past the last child. */
.toolbar > * + * {
margin-inline-start: 0.5rem;
}
/* Right: gap, no edge cases. */
.toolbar {
display: flex;
gap: 0.5rem;
}gap does not apply outside the container, does not need :last-child overrides, and survives wrapping. Tailwind utilities (gap-2, gap-x-4) compile to the same property; see tailwind.
Read flex as grow shrink basis
The shorthand flex: 1 1 0 is three values: how the item grows, how it shrinks, and its starting size before distribution.
.sidebar {
flex: 0 0 240px;
} /* fixed width, no grow, no shrink */
.main {
flex: 1 1 0;
} /* fill remaining space */
.button {
flex: 0 0 auto;
} /* size to content */Common shorthands:
flex: 1means1 1 0%. Fills remaining space, ignores intrinsic size.flex: automeans1 1 auto. Fills but respects intrinsic size first.flex: nonemeans0 0 auto. Locked to content.
If two siblings both have flex: 1 and one keeps overflowing, the 0 basis is the reason; switch one to flex: auto.
Reach for align-content only when wrapping
align-items runs on every flex container. align-content runs only when items wrap onto multiple lines. A common bug:
/* Does nothing without flex-wrap. */
.row {
display: flex;
align-content: center;
}
/* Works: wraps then aligns the lines. */
.row {
display: flex;
flex-wrap: wrap;
align-content: center;
gap: 1rem;
}If align-content looks broken, check that flex-wrap is on.
Set min-width: 0 on flex children that should shrink
Every flex item defaults to min-width: auto, which means “do not shrink below intrinsic content size.” A long word or a wide table inside a flex: 1 child overflows the container instead of compressing. Fix it explicitly:
.main {
flex: 1 1 0;
min-width: 0;
}
.main pre {
overflow-x: auto;
}Same trick for min-height: 0 when items overflow vertically. Pair with overflow to recover scrolling instead of layout breakage.
Common pitfalls
- Centering a single item:
place-items: center. On a flex container,place-itemsshorthandsalign-items(works) andjustify-items(ignored). Usejustify-content: center; align-items: center;or switch to grid. flex-direction: columnand percentage heights. Percentage heights need a defined parent height; flex columns often inheritautoand silently collapse. Defineheightormin-heighton the container.- Overflow that scrolls the wrong axis. A flex column with overflowing children needs
overflow: hiddenon the row and the column, plusmin-height: 0. See the rule above. - Wrap on a fixed-width container. Items wrap based on basis plus content, not container width. Set basis explicitly with
flex-basisorflex: 0 0 <size>. - Order property breaks tab order.
order: -1reorders visually only; keyboard users still tab in DOM order. See accessibility.