CSS Flexbox: Main Axis, Cross Axis, and When to Reach for It
How flexbox actually works — main axis vs cross axis, justify-content vs align-items, wrap, gap, and when to use grid instead.
Every flexbox bug I’ve ever chased comes down to the same confusion: which axis am I actually working on. justify-content: center does nothing, align-items does nothing, and the fix turns out to be swapping the two properties. Once that clicks, flexbox stops being a guessing game.
If you’d rather click through the options than read about them, the CSS Flexbox Generator lets you toggle every property and watch a row of boxes rearrange itself live. Here’s what’s actually happening underneath.
There are two axes, and direction decides which is which
display: flex alone doesn’t do much visually. The real work starts with flex-direction, which picks a main axis (row by default, left to right). Everything else is defined relative to that axis, not to the screen.
justify-contentworks along the main axisalign-itemsworks along the cross axis, perpendicular to it
Switch flex-direction from row to column and the main axis rotates 90 degrees. Your justify-content: center used to center things horizontally; now it centers them vertically, and align-items swaps to horizontal. Nothing about those two properties changed; the axis under them did. In my experience this one fact resolves more “flexbox isn’t working” questions than any other single explanation.
justify-content has six values worth knowing
flex-start— default, items pack toward the startflex-end— items pack toward the endcenter— items cluster in the middlespace-between— first and last items touch the edges, remaining space splits evenly between the restspace-around— every item gets equal space on both sides, so edge items appear to have half as much gap as middle itemsspace-evenly— every gap, including the outer edges, is exactly equal
People reach for space-between most often, then get confused when the outer edges look tighter than the inner gaps. That’s space-around doing exactly what it’s supposed to. If you want uniform spacing everywhere, reach for space-evenly instead.
align-items: stretch is the default, and it’s invisible until it isn’t
stretch is what you get with no align-items set at all, and it only shows up when an item has no fixed size on the cross axis. Give every item an explicit height in a row layout and stretch has nothing left to do; the items already fill the space you told them to. Remove that height and suddenly they all snap to the container’s full height. It looks like the property “started working,” but really it was working the whole time.
Wrap turns overflow into a second line instead of a squeeze
Without flex-wrap, items that don’t fit on one line get squeezed. Flexbox will shrink them below their natural width before it lets them overflow, sometimes down to nothing. flex-wrap: wrap changes the strategy entirely: items that no longer fit drop to a new line, and each line behaves like its own independent flex container for cross-axis alignment. wrap-reverse does the same thing but stacks new lines above the first instead of below.
This is the fix for the classic “my flex items are unreadably narrow on mobile” bug. Nine times out of ten the container just needed flex-wrap: wrap.
Use gap, not margin, for spacing
.container {
display: flex;
gap: 12px;
}
gap puts space strictly between items. Nothing gets added before the first item or after the last one, so you can finally drop the :last-child { margin-right: 0 } hack. Every major browser has supported gap in flexbox since early 2021 — I still see people avoid it out of habit, not necessity.
Flexbox or grid?
Flexbox is one-dimensional: it lays out a row or a column and lets content dictate size, which is exactly right for a navbar, a button row, or a card’s internal layout. Grid is two-dimensional and earns its keep when you need row and column control at once, think a page shell, a photo gallery, a dashboard. I still default to flexbox first and only switch to grid once I catch myself trying to align things across two dimensions at the same time.
Try the properties yourself in the CSS Flexbox Generator — flip direction, justify, and align until the preview matches what you had in your head, then copy the container CSS straight out.