CSS Flexbox — Complete Guide to flex-direction, justify-content, and align-items
Flexbox aligns items in one dimension — a row or a column. Here's how flex-direction, justify-content, align-items, flex-grow, and the other Flexbox properties work with visual...
Flexbox (Flexible Box Layout) is the CSS layout model for one-dimensional layouts — either a row or a column. It replaced the float-and-clear hacks developers used for years and made centering elements trivially easy.
Use the Flexbox Generator to build Flexbox layouts visually and copy the generated CSS.
How Flexbox works
Flexbox operates on two elements: the flex container and its flex items.
.container {
display: flex; /* Activate flexbox */
}
Any element with display: flex becomes a flex container. Its direct children become flex items automatically. No class needed on the children.
<div class="container"> <!-- flex container -->
<div>Item 1</div> <!-- flex item -->
<div>Item 2</div> <!-- flex item -->
<div>Item 3</div> <!-- flex item -->
</div>
The two axes
Every Flexbox layout has two axes:
- Main axis: the direction flex items are placed (controlled by
flex-direction) - Cross axis: perpendicular to the main axis
Understanding which axis is “main” and which is “cross” is essential for using justify-content and align-items correctly.
With flex-direction: row (default):
- Main axis: horizontal (left → right)
- Cross axis: vertical (top → bottom)
With flex-direction: column:
- Main axis: vertical (top → bottom)
- Cross axis: horizontal (left → right)
flex-direction
Controls the direction of the main axis:
.container {
flex-direction: row; /* Default: left to right */
flex-direction: row-reverse; /* Right to left */
flex-direction: column; /* Top to bottom */
flex-direction: column-reverse; /* Bottom to top */
}
Changing flex-direction also changes which property controls which axis. After flex-direction: column:
justify-contentcontrols vertical alignment (main axis is now vertical)align-itemscontrols horizontal alignment (cross axis is now horizontal)
This is the most common Flexbox confusion — what justify-content does visually depends entirely on flex-direction.
justify-content
Controls alignment along the main axis (how items are distributed in the row/column direction):
.container {
justify-content: flex-start; /* Default: pack items to start */
justify-content: flex-end; /* Pack items to end */
justify-content: center; /* Center items */
justify-content: space-between; /* Even gaps between items, no edge gap */
justify-content: space-around; /* Even gaps around items (half-gap at edges) */
justify-content: space-evenly; /* Perfectly equal gaps everywhere */
}
Visual reference (flex-direction: row)
flex-start: [1][2][3] ← items at left
flex-end: [1][2][3] ← items at right
center: [1][2][3] ← items centered
space-between: [1] [2] [3] ← full gaps between, no edge gaps
space-around: _[1]__[2]__[3]_ ← half-gaps at edges
space-evenly: _[1]___[2]___[3]_ ← equal gaps everywhere
align-items
Controls alignment along the cross axis (perpendicular to flex-direction):
.container {
align-items: stretch; /* Default: fill cross axis */
align-items: flex-start; /* Align to start of cross axis */
align-items: flex-end; /* Align to end of cross axis */
align-items: center; /* Center on cross axis */
align-items: baseline; /* Align text baselines */
}
With flex-direction: row, align-items controls vertical alignment.
The most useful pattern: justify-content: center + align-items: center = perfectly centered content (horizontal and vertical).
.container {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh; /* Make container fill viewport */
}
This replaces the old position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%) hack.
flex-wrap
By default, flex items try to fit on one line, shrinking if needed. flex-wrap controls what happens when they overflow:
.container {
flex-wrap: nowrap; /* Default: all items on one line, may shrink */
flex-wrap: wrap; /* Items wrap to next line when needed */
flex-wrap: wrap-reverse; /* Items wrap to previous line */
}
Use flex-wrap: wrap for responsive layouts where items should flow to the next row rather than shrink below a minimum size.
The flex shorthand
flex is shorthand for three properties: flex-grow, flex-shrink, and flex-basis.
.item {
flex: 1; /* flex-grow:1, flex-shrink:1, flex-basis:0 */
flex: 2; /* flex-grow:2, flex-shrink:1, flex-basis:0 */
flex: 0 0 200px; /* flex-grow:0, flex-shrink:0, flex-basis:200px (fixed width) */
flex: 1 0 auto; /* flex-grow:1, flex-shrink:0, flex-basis:auto */
}
flex-grow
Controls how much an item expands to fill available space (relative to other items):
/* Three items: ratios are 1:2:1 */
.item-a { flex-grow: 1; } /* Gets 25% of extra space */
.item-b { flex-grow: 2; } /* Gets 50% of extra space */
.item-c { flex-grow: 1; } /* Gets 25% of extra space */
flex: 1 on all items makes them equal-width (like width: 33.33% but responsive).
flex-shrink
Controls how much an item shrinks when there’s not enough space (relative to other items):
.item-a { flex-shrink: 1; } /* Default: shrinks proportionally */
.item-b { flex-shrink: 0; } /* Never shrinks — maintains flex-basis size */
Use flex-shrink: 0 for items that have a fixed size (like a sidebar or logo).
flex-basis
Sets the initial size of an item before grow/shrink:
.item { flex-basis: 200px; } /* Start at 200px, then grow/shrink */
.item { flex-basis: 30%; } /* Start at 30% of container */
.item { flex-basis: auto; } /* Use item's natural size (default) */
.item { flex-basis: 0; } /* All space is "extra" — grow from zero */
flex: 1 (which sets flex-basis: 0) and flex: 1 1 auto behave differently when items have varying content lengths. With flex-basis: 0, all items start at the same size and grow equally. With flex-basis: auto, items start at their content size and then grow by the same amount — which can result in unequal final sizes.
align-self
Override align-items for individual items:
.container { align-items: center; }
.special-item {
align-self: flex-end; /* This item aligns to the bottom while others are centered */
}
gap
gap sets the spacing between flex items (replaces the margin hacks):
.container {
display: flex;
gap: 16px; /* Same gap in both directions */
gap: 16px 8px; /* row-gap: 16px, column-gap: 8px */
row-gap: 16px; /* Only row gaps */
column-gap: 8px; /* Only column gaps */
}
gap is supported in all modern browsers (Chrome 84+, Firefox 63+, Safari 14.1+). It’s now the preferred way to add spacing between flex items — much cleaner than margin: 0 8px on each item.
order
Control the visual order of items without changing the HTML:
.item-last-in-html { order: -1; } /* Appears first visually */
.item-first-in-html { order: 2; } /* Appears last visually */
/* Default order for all items is 0 */
Use sparingly — changing visual order while leaving DOM order unchanged affects screen reader navigation and keyboard focus order.
Common Flexbox patterns
Navigation bar
.nav {
display: flex;
align-items: center;
gap: 16px;
padding: 0 24px;
}
.nav-logo { margin-right: auto; } /* Pushes nav links to the right */
The margin-right: auto on the logo pushes all other items to the far right, creating a common nav pattern.
Card grid (equal-height cards)
.card-container {
display: flex;
flex-wrap: wrap;
gap: 24px;
}
.card {
flex: 1 1 280px; /* Grow, shrink, min 280px */
display: flex;
flex-direction: column; /* Stack content vertically */
}
.card-footer {
margin-top: auto; /* Push footer to bottom of card */
}
flex: 1 1 280px creates a fluid grid: cards fill the row at minimum 280px each, wrapping to the next row when they don’t fit.
Sticky footer
body {
display: flex;
flex-direction: column;
min-height: 100vh;
}
main { flex: 1; } /* Main grows to fill available space */
footer { /* Stays at bottom */ }
Centered hero section
.hero {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
min-height: 80vh;
gap: 24px;
}
Flexbox vs Grid
Flexbox is one-dimensional (row OR column). CSS Grid is two-dimensional (rows AND columns).
| Use Flexbox when | Use Grid when |
|---|---|
| Laying out items in a single row or column | Creating a two-dimensional layout |
| Content-driven layout (items determine size) | Layout-driven content (grid determines size) |
| Navigation bars, card rows, button groups | Full-page layouts, card grids with defined columns |
| You want items to naturally wrap | You need explicit column/row control |
They’re complementary — use Grid for the page layout, Flexbox for components within grid areas.
The Flexbox Generator
The Flexbox Generator lets you visually toggle all the container and item properties and see the result in real time. Copy the generated CSS for use in your project. It’s useful for:
- Learning what each property does visually
- Finding the right combination of
justify-contentandalign-itemsfor a specific layout - Generating starter CSS for a new component
Related tools
- Flexbox Generator — build Flexbox layouts visually
- CSS Grid Generator — build CSS Grid layouts
- Box Shadow Generator — CSS box-shadow values
Related posts
- CSS Flexbox Cheatsheet — Every Property with Visual Examples — CSS Flexbox has 12 container properties and 6 item properties. Here's a complete…
- CSS flex-order Property — Reorder Flex Items Without Changing HTML — The CSS order property reorders flex items visually without changing the DOM. Le…
- CSS flex-grow, flex-shrink, flex-basis — The Flex Property Explained — The CSS flex shorthand controls three properties: flex-grow (how much to expand)…
Related tool
Visual CSS Flexbox playground. Live preview + copyable CSS. Control direction, wrap, justify, align, gap. Example child layouts.
Written by Mian Ali Khalid. Part of the Frontend & Design pillar.