4 min read
On this page

Flexbox

The One-Dimensional Layout Tool

Flexbox handles layout in one direction at a time -- either a row or a column. It distributes space among items, aligns them, and handles wrapping. Before flexbox, centering an element vertically required hacks. Now it takes three lines.

.container {
  display: flex;
  justify-content: center;
  align-items: center;
}

Flex Container & Flex Items

When you set display: flex on an element, it becomes a flex container. Its direct children become flex items.

<div class="container">
  <div class="item">One</div>
  <div class="item">Two</div>
  <div class="item">Three</div>
</div>
.container {
  display: flex;
}
Before (block):       After (flex):
┌──────────┐          ┌───┬───┬─────┐
│   One    │          │One│Two│Three│
├──────────┤          └───┴───┴─────┘
│   Two    │
├──────────┤
│  Three   │
└──────────┘

Flex items are laid out along the main axis by default in a row.

Axes

Flexbox has two axes:

  • Main axis: The direction items are laid out (default: horizontal, left to right)
  • Cross axis: Perpendicular to the main axis (default: vertical, top to bottom)
/* Main axis: horizontal (default) */
.row {
  display: flex;
  flex-direction: row;
}

/* Main axis: vertical */
.column {
  display: flex;
  flex-direction: column;
}

/* Reversed */
.row-reverse {
  display: flex;
  flex-direction: row-reverse;  /* Right to left */
}

Understanding which axis is which determines how justify-content and align-items behave. justify-content always works on the main axis. align-items always works on the cross axis.

Justify-Content (Main Axis)

Controls how items are distributed along the main axis.

.container {
  display: flex;
  justify-content: flex-start;    /* Default: items at the start */
}
flex-start:      │One Two Three              │
flex-end:        │              One Two Three│
center:          │       One Two Three       │
space-between:   │One       Two       Three  │
space-around:    │  One     Two     Three    │
space-evenly:    │   One    Two    Three     │
  • space-between: Equal space between items, no space at edges
  • space-around: Equal space around each item (edges get half-space)
  • space-evenly: Equal space between all items and edges

Align-Items (Cross Axis)

Controls how items are aligned along the cross axis.

.container {
  display: flex;
  align-items: stretch;  /* Default: items stretch to fill container height */
}

Values: stretch (default, fill container height), flex-start (top), flex-end (bottom), center (vertically centered), baseline (align by text baseline).

Align-Self (Individual Item)

Override the container's align-items for a specific item:

.container {
  display: flex;
  align-items: flex-start;
}

.special-item {
  align-self: flex-end;  /* This one sits at the bottom */
}

Gap

Space between flex items without margins:

.container {
  display: flex;
  gap: 16px;          /* Equal row and column gap */
  /* Or separately: */
  row-gap: 16px;
  column-gap: 24px;
}

gap is cleaner than margins because it only adds space between items, not around the edges. No more "negative margin on the container" hacks.

Flex-Grow, Flex-Shrink & Flex-Basis

These three properties control how items share available space.

flex-basis

Sets the initial size of an item before growing or shrinking. It functions like width (in a row) or height (in a column) but is specific to flex layout.

.item {
  flex-basis: 200px;  /* Start at 200px */
}

flex-grow

Determines how much an item grows relative to siblings when there is extra space.

.container {
  display: flex;
  width: 600px;
}

.item-a { flex-grow: 1; }  /* Gets 1 share of extra space */
.item-b { flex-grow: 2; }  /* Gets 2 shares of extra space */
.item-c { flex-grow: 1; }  /* Gets 1 share of extra space */

If each item starts at 100px (300px used, 300px remaining), item-b gets 150px of the extra space and the others get 75px each.

flex-shrink

Determines how much an item shrinks when there is not enough space. Default is 1 (items shrink equally). Set to 0 for fixed-width elements that should never shrink.

The Flex Shorthand

The flex property combines all three:

/* flex: grow shrink basis */
.item { flex: 0 1 auto; }    /* Default: don't grow, can shrink, auto size */
.item { flex: 1; }            /* Shorthand for: 1 1 0% -- grow equally */
.item { flex: 1 0 200px; }    /* Grow from 200px base, never shrink */
.item { flex: none; }         /* Shorthand for: 0 0 auto -- rigid size */

Use the shorthand. flex: 1 is clearer than setting three separate properties.

Wrapping

By default, flex items squeeze onto one line. Enable wrapping:

.container {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
}

.item {
  flex: 1 1 250px;  /* Grow, shrink, start at 250px */
}

Items that cannot fit on the current line wrap to the next. Combined with a flex-basis, this creates responsive layouts without media queries. Use align-content to control spacing between wrapped lines.

Common Patterns

Centering (The Classic)

.center-everything {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
}
.nav {
  display: flex;
  align-items: center;
  gap: 24px;
  padding: 0 16px;
}

.nav-logo {
  margin-right: auto;  /* Pushes everything else to the right */
}
<nav class="nav">
  <a href="/" class="nav-logo">Logo</a>
  <a href="/products">Products</a>
  <a href="/about">About</a>
  <a href="/contact">Contact</a>
</nav>
.layout {
  display: flex;
  min-height: 100vh;
}

.sidebar {
  flex: 0 0 250px;   /* Fixed 250px width, never grow or shrink */
}

.main-content {
  flex: 1;            /* Takes remaining space */
  padding: 24px;
}

Flexbox vs Grid

Use Case Flexbox Grid
One-dimensional layout (row OR column) Yes Overkill
Two-dimensional layout (rows AND columns) Hacks required Yes
Content-driven sizing Yes Less natural
Precise grid placement No Yes
Navigation bars Yes Can work
Card grids Wrapping flex Better with grid
Full page layouts Possible Better with grid
Centering a single element Yes Yes

Rule of thumb: Use flexbox for components (nav bars, card rows, input groups). Use grid for page layouts and two-dimensional grids.

Common Pitfalls

  • Forgetting that justify-content follows the main axis: In flex-direction: column, justify-content controls vertical distribution, not horizontal. This trips people up constantly.
  • Not using min-width: 0 on flex items: Flex items have an implicit min-width: auto, which prevents them from shrinking below their content size. Text can overflow. Add min-width: 0 to allow shrinking.
  • Using flex: 1 when you want a fixed size: flex: 1 means "grow to fill space." For a fixed-width sidebar, use flex: 0 0 250px.
  • Nesting too many flex containers: If you are nesting more than two or three levels, consider whether grid would simplify the layout.
  • Forgetting flex-wrap: wrap: Without wrapping, items squeeze onto one line and can overflow or become unusably small.

Key Takeaways

  • Flexbox is a one-dimensional layout tool: row or column, not both
  • justify-content aligns on the main axis; align-items aligns on the cross axis
  • flex: 1 makes items grow equally; flex: none makes items rigid
  • gap is the clean way to space items (no margin hacks)
  • margin-right: auto (or margin-left: auto) pushes items apart -- useful for navigation patterns
  • Wrapping with flex-wrap: wrap and a flex-basis creates responsive layouts
  • Use flexbox for components; use grid for page-level layouts and two-dimensional grids
  • The flex shorthand (flex: grow shrink basis) is the idiomatic way to set flex properties