Flexbox solves one-dimensional layout — distributing space along a single row or column. Most real-world component layout (nav bars, cards, form rows, centering) is flexbox, not grid, and knowing exactly which axis each property controls is the difference between fighting the layout and using it.
cssflexboxlayoutalignment
Knowledge Check
4 questions · pass at 70%
0/4
mediummcq
1. With `flex-direction: column`, which property controls horizontal alignment of items?
Interview Questions
3 questions
Cheatsheet
Download-ready reference
Cheatsheet
display: flex; → one-dimensional layout along a MAIN axis + CROSS axis
Axis depends on flex-direction:
row (default) main = horizontal → cross = vertical ↕
column main = vertical ↕ cross = horizontal →
Container properties:
justify-content ALWAYS main axis: flex-start | flex-end | center | space-between | space-around | space-evenly
align-items ALWAYS cross axis: stretch | flex-start | flex-end | center | baseline
flex-wrap nowrap (default) | wrap | wrap-reverse
gap spacing between items — prefer over margin hacks
Item properties:
flex-grow (0) share of EXTRA space
flex-shrink (1) share of space removed when tight — items shrink by DEFAULT
flex-basis (auto) starting size before grow/shrink applied
flex: 1 = 1 1 0% → equal share, ignores content size
flex: auto = 1 1 auto → grow/shrink from content's natural size
flex: none = 0 0 auto → rigid, never grows or shrinks
flex: 0 0 200px → fixed 200px
align-self per-item override of container's align-items
order VISUAL reorder only — does NOT change DOM/tab/reading order
Common gotchas:
flex-shrink defaults to 1 → fixed width can still shrink; use flex-shrink:0 to prevent
flex items have implicit min-width:auto → blocks text-overflow:ellipsis until min-width:0 set
Quick recipes:
Center both axes: justify-content: center; align-items: center;
Equal columns: display:flex; > * { flex: 1; }
Sticky footer: body{display:flex;flex-direction:column;min-height:100vh} main{flex:1}
Wrap with gaps: flex-wrap: wrap; gap: 1rem;
Flexbox (Flexible Box Layout) is a one-dimensional layout model — it distributes space and aligns items along a single axis at a time (a row, or a column). This is the key distinction from Grid, which is two-dimensional (rows and columns simultaneously). The practical rule of thumb: reach for flexbox when laying out items in a line (a nav bar, a button group, a card's internal content, centering something), reach for Grid when you need to control both rows and columns together (a page layout, a photo gallery, a dashboard).
The two axes — the single most important mental model#
.container { display: flex; flex-direction: row; /* default: main axis is horizontal */}
Every flex property is defined relative to one of two axes, and which axis is "main" depends entirely on flex-direction:
Main axis — the direction items are laid out (row = horizontal, column = vertical).
justify-content always controls the main axis. align-items/align-content always control the cross axis. This single fact resolves 90% of "why isn't my centering working" confusion — if you set flex-direction: column and use justify-content: center expecting horizontal centering, it won't work, because in a column, justify-content is now controlling vertical space.
/* Perfect centering, both axes, regardless of direction */.container { display: flex; justify-content: center; /* main axis */ align-items: center; /* cross axis */}
justify-content: space-between vs space-around vs space-evenly is a common point of confusion:
space-between — no space at the container edges, equal space between items.
space-around — equal space around each item (so edge gaps are half the between-item gap).
space-evenly — truly equal space everywhere, including edges.
Item properties — the flex-grow/shrink/basis triad#
.item { flex-grow: 0; /* how much this item grows relative to siblings when there's extra space */ flex-shrink: 1; /* how much this item shrinks relative to siblings when space is tight */ flex-basis: auto; /* the item's starting size before growing/shrinking is applied */ /* shorthand — almost always what you actually want to write */ flex: 0 1 auto; /* grow shrink basis */}
flex-basis is not the same as width.flex-basis sets the starting point for space distribution along the main axis; the browser then applies flex-grow/flex-shrink on top of it. If flex-direction: column, flex-basis controls the starting height, not width — another axis-relativity gotcha.
Common shorthand patterns:
.item { flex: 1; } /* flex: 1 1 0% — grow and shrink equally, ignore content size, "take equal share" */.item { flex: auto; } /* flex: 1 1 auto — grow and shrink, but starting from content size */.item { flex: none; } /* flex: 0 0 auto — rigid, never grows or shrinks */.item { flex: 0 0 200px; } /* fixed 200px, never grows or shrinks */
flex: 1 (equal-share items ignoring their content's natural size) and flex: auto (starts from content size, then grows/shrinks) look similar but produce different results when items have different amounts of content — this distinction trips people up constantly.
.item-3 { order: -1; } /* moves visually first, without changing DOM/tab order */
Important:order only changes visual order — it does not change DOM order, tab order, or reading order for screen readers. Using it to reorder content in a way that no longer matches the visual flow creates exactly the keyboard/screen-reader mismatch covered in the Accessibility topic — a sighted keyboard user tabbing through will jump in an order that doesn't match what they see.
1. Confusing which axis justify-content vs align-items controls#
Covered above — the #1 flexbox confusion. Remember: main axis = justify-content, cross axis = align-items, and which is which flips with flex-direction.
/* Old workaround — extra margin on every item except the last, fragile */.item:not(:last-child) { margin-right: 1rem; }/* Modern — just this */.container { display: flex; gap: 1rem; }
gap (broadly supported in flexbox since ~2021) is simpler, doesn't need :last-child exceptions, and correctly handles flex-wrap (spacing between wrapped rows too, which margin-based approaches handle awkwardly).
3. Expecting flex: 1 and flex: auto to behave the same#
<div style="display:flex"> <div style="flex: 1">Short</div> <div style="flex: 1">A much longer piece of content here</div></div>
With flex: 1, both items end up equal width regardless of content length (content size is ignored as the basis). With flex: auto instead, the longer item's natural content size influences its starting width before grow/shrink is applied, so they won't necessarily end up equal. Pick deliberately based on which behavior you actually want.
4. Setting a fixed width on a flex item and being surprised it still shrinks#
.item { width: 200px; } /* flex-shrink defaults to 1 — this can still shrink below 200px */
flex-shrink: 1 is the default — a flex item with only width set (no flex-shrink: 0) will still shrink if the container is tight on space. If you need a genuinely fixed size, use flex: 0 0 200px or add flex-shrink: 0 explicitly.
5. Using order to fix a visual layout mistake instead of the source markup order#
Reordering via CSS order when the correct fix is reordering the actual DOM creates a silent accessibility mismatch (see Concept section) — reserve order for genuinely presentation-only reordering (e.g. a "featured" card visually first on desktop but not meaningfully different in importance), not as a patch for wrong source order.
6. Forgetting min-width: 0 on flex items containing text/long content#
/* A flex item won't shrink below its content's intrinsic minimum size by default, which can cause overflow with long unbreakable text (URLs, long words) */.item { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
Flex items have an implicit min-width: auto (roughly, "don't shrink smaller than my content needs"), which can prevent text truncation (text-overflow: ellipsis) from working until you explicitly override it with min-width: 0.