A little help goes a long way. Find a tool/

Design FIELD NOTES · 4 MIN READ

CSS Flexbox: The Container Properties That Matter

flex-direction, justify-content, align-items, flex-wrap and gap — how the flex container actually positions its items.

Flexbox confuses people for one reason: it has two coordinate systems pretending to be one. Items flow along a main axis and are aligned on a cross axis, and which property moves things left-right versus up-down depends entirely on the direction you chose. Master that swap and the five container properties stop being a cheat sheet and start being obvious.

display: flex changes what the children are

Setting display: flex on an element makes it a flex container and turns its direct children into flex items — block-level behavior for them disappears, margins stop collapsing, and they line up on one line by default. The container is the only thing the five famous properties apply to; the items are shaped by flex-grow, flex-shrink, and flex-basis, which is the other half of the model and a topic of its own.

flex-direction: the axis switch

flex-direction picks which way items flow: row (the default) lays them left to right, column stacks them top to bottom, and the -reverse variants reverse the flow within the same axis. The direction defines the main axis — everything else keys off it. A practical consequence: with row-reverse or column-reverse, visual order and DOM order diverge, which screen readers still follow in DOM order — so reverse the flow only when the reading order stays sensible.

justify-content: distributing along the main axis

justify-content answers "what happens to the free space along the flow direction?". flex-start (the default) packs items at the start and dumps all free space at the end; center splits the space around the group; space-between pushes the leftovers into the gaps between items; space-around gives every item half a gap on each side; space-evenly makes all gaps identical. None of these change item sizes — they only position the group and the spaces around it.

display: flex;
justify-content: space-between;   /* first flush left, last flush right */

The classic navigation bar is exactly this: logo at the start, links distributed, last item flush with the far edge.

align-items: the cross-axis behavior

align-items positions items on the cross axis, and its default is the one people never realize they are using: stretch. Items without an explicit cross-axis size grow to fill the container — which is why flexbox equalizes card heights for free in a row. center is the famous one (true vertical centering with two lines of CSS), flex-start and flex-end pack to the cross-axis edges, and baseline aligns items by the baseline of their first line of text, which is what you want when mixing headings and buttons on one row.

Here is the swap in action: with flex-direction: row, justify-content moves items horizontally and align-items vertically; with column, the roles reverse. When a layout "does nothing" after you tweak a property, check the direction first — you are probably pushing along the axis you were not looking at.

flex-wrap and the gap between items

By default (nowrap) items refuse to leave one line and will shrink to fit. wrap lets them spill onto new lines, which turns the container into a de facto multi-row layout — and makes align-content relevant, since it distributes the rows themselves when there is cross-axis space to spare.

For spacing, gap is the modern answer: gap: 12px puts exactly 12px between items and nothing at the container's edges. Margins require :last-child cleanup and misbehave when wrapping starts new rows; gap handles both axes at once and survives reordering, filtering, and responsive item counts untouched.

The minimal declaration habit

Four of the five properties have CSS initial values — row, flex-start, stretch, nowrap — so a container that omits them renders identically to one that writes them out. Writing only the deltas keeps stylesheets reviewable: display: flex; justify-content: space-between; gap: 12px; is a complete navbar container. Emit the full set only when the CSS doubles as documentation, and be consistent about which style a codebase uses.

Try it yourself

The CSS Flexbox Generator builds the container block from the five properties, previews the exact declarations on sample boxes, and writes only the non-default lines unless you ask for more. When placement needs rows and columns simultaneously, the CSS Grid Generator owns the track skeleton instead. And when the container also needs depth, the CSS Box Shadow Generator layers the elevation on top.

Frequently asked questions

What are the main axis and cross axis?
The main axis is the direction items flow — set by flex-direction — and the cross axis is perpendicular to it. justify-content distributes items along the main axis; align-items aligns them on the cross axis. Switching row to column swaps which property moves things horizontally or vertically.
Why is my flex item overflowing instead of shrinking?
The default flex-shrink is 1, but items refuse to shrink below their minimum content size. Long words or wide tables set a high min-width; fix it with min-width: 0 on the item, or let it wrap rather than shrink.
Does gap work in flexbox?
Yes — gap is the modern way to space flex items, applying only between them with no stray margin on the ends. It applies to both axes, so wrapped rows get row gaps automatically.
What does align-items: stretch do?
It is the default: items without a set cross-axis size stretch to fill the container's cross size. That is why flex rows equalize card heights for free — and why an explicit height or align-self stops an item from stretching.