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 edgesspace-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;
}
Navigation Bar
.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>
Sidebar Layout
.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-contentfollows the main axis: Inflex-direction: column,justify-contentcontrols vertical distribution, not horizontal. This trips people up constantly. - Not using
min-width: 0on flex items: Flex items have an implicitmin-width: auto, which prevents them from shrinking below their content size. Text can overflow. Addmin-width: 0to allow shrinking. - Using
flex: 1when you want a fixed size:flex: 1means "grow to fill space." For a fixed-width sidebar, useflex: 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-contentaligns on the main axis;align-itemsaligns on the cross axisflex: 1makes items grow equally;flex: nonemakes items rigidgapis the clean way to space items (no margin hacks)margin-right: auto(ormargin-left: auto) pushes items apart -- useful for navigation patterns- Wrapping with
flex-wrap: wrapand aflex-basiscreates 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