DeepFrontend
Practice ArenaBlogSign in
Go Pro
DeepFrontend

Interview-grade learning paths and hands-on practice for mid-to-senior engineers. Master internals, patterns, and system architecture with runnable code.

All systems operational

Core Courses

  • -JavaScript Internals
  • -React Reconciliation
  • -TypeScript rigor
  • -Next.js Caching
  • -Node.js Event Loop
  • -System Design
  • -Web Security
  • -CSS & Page Layouts

Explore

  • Learning Paths
  • Practice Arena
  • Pricing Options
  • HTML Sitemap

Resources

  • Privacy Policy
  • Terms of Service
  • Email Support

© 2026 DeepFrontend. All rights reserved.

Expert learning environments for web engineering teams.

Home/CSS/Flexbox
beginner25 min read·Updated Jul 2026

Flexbox

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;

Related topics

GridPositioningResponsive Design

On this page

25m
Knowledge CheckInterview QuestionsCheatsheet

Concept#

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).
  • Cross axis — perpendicular to the main axis.
.container { flex-direction: row; }    /* main = horizontal, cross = vertical */
.container { flex-direction: column; } /* main = vertical, cross = horizontal */

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 */
}

Container properties#

.container {
  display: flex;
  flex-direction: row | row-reverse | column | column-reverse;
  flex-wrap: nowrap | wrap | wrap-reverse;
  justify-content: flex-start | flex-end | center | space-between | space-around | space-evenly;



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.

align-self — per-item cross-axis override#

.item {
  align-self: flex-start | flex-end | center | baseline | stretch; /* overrides the container's align-items for this one item */
}

order — visual reorder without touching the DOM#

.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.

Common patterns#

/* Perfect centering (both axes) */
.center { display: flex; justify-content: center; align-items: center; }
 
/* Nav bar: logo left, links right */
.nav { display: flex; justify-content: space-between; align-items: center; }
 
/* Equal-width columns */
.columns { display: flex









Common Mistakes#

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.

2. Using margin for gaps instead of gap#

/* 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.


Best Practices#

  • Identify the main axis first (flex-direction), then reason about justify-content/align-items relative to it — don't guess.
  • Use gap for spacing between items, not margin hacks.
  • Choose flex: 1 vs flex: auto vs flex: none deliberately based on whether content size should influence the starting size.
  • Add flex-shrink: 0 (or use the flex shorthand) for anything that must never shrink — icons, avatars, fixed-width sidebars.

Further Resources#

  • MDN — Flexbox
  • CSS-Tricks — A Complete Guide to Flexbox — the most-referenced visual guide on the web.
  • Flexbox Froggy — interactive game for learning flexbox properties.
  • web.dev — Flexbox
  • Josh W. Comeau — An Interactive Guide to Flexbox

align-items
:
stretch
|
flex-start
|
flex-end
|
center
|
baseline
;
align-content: /* same values as justify-content — only matters with flex-wrap + multiple lines */
gap: 1rem; /* modern, preferred over margin hacks for spacing between items */
}
; }
.columns > * { flex: 1; }
/* Sticky footer (footer stays at bottom even with little content) */
body { display: flex; flex-direction: column; min-height: 100vh; }
main { flex: 1; } /* grows to fill available space, pushing footer down */
/* Responsive wrap with consistent gaps */
.cards { display: flex; flex-wrap: wrap; gap: 1rem; }
.cards > * { flex: 1 1 250px; } /* grow/shrink, but never smaller than 250px comfortably */
  • Set min-width: 0 on flex items that need text truncation.
  • Avoid order for anything but genuinely presentation-only reordering — never use it to compensate for wrong source/DOM order.
  • Combine with flex-wrap: wrap and gap for simple responsive layouts without media queries, when items can naturally reflow.