Flexbox alignment is one of its most powerful and nuanced features. The ability to distribute space and align content along both the main axis and cross axis with a small set of intuitive properties has made Flexbox the go-to tool for component-level layouts. In this lesson you will master justify-content, align-items, align-content, align-self, and the margin: auto trick โ and know exactly when to reach for each.
Alignment Properties at a Glance
| Property | Applies To | Controls |
|---|---|---|
justify-content |
Container | Main axis โ distributes items along the primary flow |
align-items |
Container | Cross axis โ aligns all items within their line |
align-content |
Container | Cross axis โ distributes lines (only with wrap + multiple lines) |
align-self |
Individual item | Cross axis โ overrides align-items for one specific item |
order |
Individual item | Visual paint order โ does not change DOM or tab order |
justify-content Values
| Value | Space Distribution | Best For |
|---|---|---|
flex-start |
Items packed to the start edge | Default left-aligned rows |
flex-end |
Items packed to the end edge | Right-aligned button groups |
center |
Items grouped in the middle | Centered navigation, hero content |
space-between |
First and last at edges; equal gaps between | Navbars, tab bars, toolbars |
space-around |
Equal space around each item (half-gaps at edges) | Tag lists, icon rows |
space-evenly |
Truly equal gaps including outer edges | Step indicators, equal-spaced icons |
align-items vs align-content
| Property | When It Has Effect | What It Controls |
|---|---|---|
align-items |
Always โ even on a single line | How items are aligned within their row/line |
align-content |
Only when flex-wrap: wrap AND items have actually wrapped | How the lines themselves are distributed in the container |
align-content only has a visible effect when the flex container has flex-wrap: wrap AND the items have genuinely wrapped onto multiple lines. On a single-line flex container, align-content has no effect whatsoever โ use align-items instead.margin: auto trick on a flex item is extremely powerful. margin-left: auto absorbs all free space to the left of an item โ effectively pushing it to the far right of the container. This creates a “push to edge” pattern without needing an extra wrapper element or nested flex container.order property changes the visual order of items but not the DOM order. Keyboard navigation (Tab key) and screen readers still follow DOM order. Never use order to rearrange content that has a logical sequential relationship โ it creates an accessibility disconnect.Basic Example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Flexbox Alignment</title>
<style>
*, *::before, *::after { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; padding: 32px; background: #f8fafc; }
h3 { margin: 24px 0 8px; font-size: 0.8rem; text-transform: uppercase;
letter-spacing: 0.06em; color: #64748b; }
.demo-row {
display: flex;
background: #e0e7ff;
border-radius: 8px;
padding: 8px;
margin-bottom: 16px;
min-height: 80px;
gap: 8px;
}
.item {
background: #4f46e5;
color: white;
border-radius: 6px;
padding: 8px 14px;
font-size: 0.8rem;
font-weight: 700;
white-space: nowrap;
}
.item-tall { height: 60px; display: flex; align-items: center; }
/* justify-content examples */
.jc-center { justify-content: center; }
.jc-space-between { justify-content: space-between; }
.jc-space-evenly { justify-content: space-evenly; }
/* align-items examples */
.ai-center { align-items: center; }
.ai-start { align-items: flex-start; }
.ai-baseline { align-items: baseline; }
/* align-self override */
.self-end { align-self: flex-end; }
.self-start { align-self: flex-start; }
/* margin: auto push pattern */
.push-right { margin-left: auto; }
/* order */
.order-demo .item:nth-child(1) { order: 3; }
.order-demo .item:nth-child(2) { order: 1; }
.order-demo .item:nth-child(3) { order: 2; }
</style>
</head>
<body>
<h3>justify-content: center</h3>
<div class="demo-row jc-center ai-center">
<div class="item">One</div>
<div class="item">Two</div>
<div class="item">Three</div>
</div>
<h3>justify-content: space-between</h3>
<div class="demo-row jc-space-between ai-center">
<div class="item">Brand</div>
<div class="item">About</div>
<div class="item">Contact</div>
</div>
<h3>align-items: center vs flex-start (cross axis)</h3>
<div class="demo-row ai-center">
<div class="item">Normal</div>
<div class="item item-tall">Tall item</div>
<div class="item">Normal โ all centered on cross axis</div>
</div>
<h3>align-self override</h3>
<div class="demo-row ai-center">
<div class="item">Default (center)</div>
<div class="item item-tall">Tall</div>
<div class="item self-end">align-self: flex-end</div>
<div class="item self-start">align-self: flex-start</div>
</div>
<h3>margin-left: auto โ push to right</h3>
<div class="demo-row ai-center">
<div class="item">Brand</div>
<div class="item">Docs</div>
<div class="item push-right">Login (pushed right)</div>
</div>
<h3>order property (DOM order: 1,2,3 โ visual: 2,3,1)</h3>
<div class="demo-row ai-center order-demo">
<div class="item">DOM 1 (order:3)</div>
<div class="item">DOM 2 (order:1)</div>
<div class="item">DOM 3 (order:2)</div>
</div>
</body>
</html>
How It Works
Step 1 โ justify-content Distributes Main-Axis Space
After placing items at their flex-basis size, the browser calculates leftover space on the main axis. justify-content decides what to do with it โ pack items together at the start, end, or center, or distribute the surplus between or around items.
Step 2 โ align-items Stretches Items by Default
The default value of align-items is stretch, which is why flex items in a row all become the same height as the tallest item. Changing to center aligns all items to their midpoint on the cross axis โ essential for icon + text combinations.
Step 3 โ align-self Overrides for One Item
align-self on a specific flex item overrides the container’s align-items value for that item only. This is how you can have most items centered while pinning one to the bottom of a row.
Step 4 โ margin-left: auto Absorbs Free Space
Flex items can use margin: auto to absorb free space on any side. margin-left: auto on the “Login” button pulls all available horizontal space to its left, pushing the button to the container’s far-right edge โ a clean, no-wrapper navbar pattern.
Step 5 โ order Changes Visual Sequence
All flex items have order: 0 by default. Items with lower values appear first; higher values appear last. Items with equal values maintain their DOM order. Useful for mobile-first layouts where you need to reorder sections visually without restructuring HTML.
Real-World Example: Toolbar with Mixed Alignment
/* toolbar.css */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
.toolbar {
display: flex;
align-items: center;
gap: 8px;
padding: 10px 16px;
background: #1e293b;
border-radius: 10px;
min-height: 56px;
}
/* Icon button group */
.tool-group {
display: flex;
align-items: center;
gap: 4px;
}
.tool-btn {
display: flex;
align-items: center;
justify-content: center;
width: 36px;
height: 36px;
background: transparent;
border: none;
border-radius: 6px;
color: #94a3b8;
cursor: pointer;
font-size: 1rem;
transition: background 0.15s, color 0.15s;
}
.tool-btn:hover { background: #334155; color: white; }
.tool-btn.active { background: #4f46e5; color: white; }
/* Divider between groups */
.tool-divider {
width: 1px;
height: 24px;
background: #334155;
flex-shrink: 0;
}
/* Filename input โ grows to fill available space */
.file-input {
flex: 1; /* absorbs all free space */
background: #334155;
border: none;
border-radius: 6px;
color: white;
padding: 6px 12px;
font-size: 0.875rem;
font-family: system-ui, sans-serif;
min-width: 0; /* allow shrinking below content size */
}
.file-input::placeholder { color: #64748b; }
.file-input:focus { outline: 2px solid #4f46e5; }
/* Action buttons โ pushed to right with margin-left: auto */
.toolbar-actions {
display: flex;
align-items: center;
gap: 8px;
margin-left: auto; /* pushes entire group to far right */
}
.btn-save {
display: flex;
align-items: center;
gap: 6px;
padding: 7px 14px;
background: #4f46e5;
color: white;
border: none;
border-radius: 6px;
font-size: 0.8rem;
font-weight: 600;
cursor: pointer;
white-space: nowrap;
}
.btn-save:hover { background: #4338ca; }
Common Mistakes
Mistake 1 โ Using align-content on a single-line container
โ Wrong โ align-content does nothing on a single-line flex container:
.row { display: flex; align-content: center; }
/* Only one line โ align-content has no effect. Use align-items. */
โ Correct โ use align-items for single-line, align-content for multi-line:
.row { display: flex; align-items: center; }
/* Multi-line (with flex-wrap: wrap): */
.grid { display: flex; flex-wrap: wrap; align-content: center; }
Mistake 2 โ Using order to reorder semantically related content
โ Wrong โ changes visual order but keyboard/screen reader follows DOM order:
.sidebar { order: 2; } /* visually second but DOM first โ tab goes there first */
.main { order: 1; }
โ Correct โ restructure HTML so DOM order matches reading/interaction order:
<main class="main">...</main>
<aside class="sidebar">...</aside>
Mistake 3 โ Stacking justify-content and align-items on wrong axis
โ Wrong โ trying to use justify-content to center vertically in a row:
.row { display: flex; justify-content: center; } /* centers horizontally, not vertically */
โ Correct โ for a row, vertical centering uses align-items:
.row { display: flex; align-items: center; justify-content: center; }
Quick Reference
| Property | Axis | Key Values |
|---|---|---|
justify-content |
Main | flex-start, center, space-between, space-evenly |
align-items |
Cross | stretch, center, flex-start, flex-end, baseline |
align-content |
Cross (lines) | Only with flex-wrap: wrap on multi-line containers |
align-self |
Cross (one item) | Same as align-items โ overrides for that item |
order |
Visual only | Default 0; lower = earlier; does not affect DOM order |
margin-left: auto |
Main | Pushes item to far right; absorbs free space |