CSS Flexbox โ short for Flexible Box Layout โ is a one-dimensional layout system that distributes space along a single axis. It solves problems that were nearly impossible with older CSS: centering content vertically, building equal-height columns, and creating navigation bars that spread items automatically. In this lesson you will learn what a flex container is, what flex items are, and the fundamental concept of the main axis vs. the cross axis.
Flex Container vs Flex Items
| Concept | Description | How to Activate |
|---|---|---|
| Flex container | The parent element that establishes the flex formatting context | display: flex or display: inline-flex |
| Flex items | The direct children of the flex container โ they automatically become flex participants | Automatic when parent has display: flex |
| Main axis | The axis along which flex items are laid out | Controlled by flex-direction (default: horizontal) |
| Cross axis | Perpendicular to the main axis | Alignment controlled by align-items |
flex-direction Values
| Value | Main Axis Direction | Items Flow |
|---|---|---|
row (default) |
Horizontal left to right | In DOM order |
row-reverse |
Horizontal right to left | Reversed |
column |
Vertical top to bottom | In DOM order |
column-reverse |
Vertical bottom to top | Reversed |
Essential Alignment Properties
| Property | Axis | Common Values |
|---|---|---|
justify-content |
Main axis | flex-start, flex-end, center, space-between, space-around, space-evenly |
align-items |
Cross axis (all items) | stretch (default), flex-start, flex-end, center, baseline |
gap |
Both axes | Any length โ clean inter-item spacing with no margin hacks |
justify-content controls items along the main axis and align-items controls them on the cross axis. These axes swap when you change flex-direction โ in a column layout, justify-content: center centers vertically and align-items: center centers horizontally.display: flex; align-items: center; justify-content: center; on the parent. This single three-line pattern replaces hacks involving line-height, table-cell, or absolute positioning.display: flex only creates a flex context for direct children. Grandchildren remain in normal flow inside their parent flex item. Nesting flex containers inside flex items is perfectly normal and very common in real layouts.Basic Example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Flex Container Basics</title>
<style>
*, *::before, *::after { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; padding: 32px; background: #f8fafc; margin: 0; }
/* โโ Perfect vertical + horizontal centering โโ */
.hero {
display: flex;
flex-direction: column; /* main axis = vertical */
align-items: center; /* center on cross axis (horizontal) */
justify-content: center; /* center on main axis (vertical) */
min-height: 220px;
background: linear-gradient(135deg, #4f46e5, #7c3aed);
border-radius: 16px;
padding: 32px;
gap: 16px;
color: white;
margin-bottom: 24px;
}
.hero h1 { margin: 0; font-size: 1.75rem; text-align: center; }
.hero p { margin: 0; opacity: 0.85; text-align: center; max-width: 44ch; line-height: 1.6; }
/* โโ Horizontal navbar with space-between โโ */
.navbar {
display: flex;
align-items: center;
justify-content: space-between; /* brand left, links right */
padding: 12px 24px;
background: #1e293b;
border-radius: 10px;
margin-bottom: 24px;
}
.navbar-brand { color: white; font-weight: 700; font-size: 1.1rem; }
.navbar-links { display: flex; gap: 8px; list-style: none; margin: 0; padding: 0; }
.navbar-links a {
color: #94a3b8; text-decoration: none;
padding: 6px 12px; border-radius: 6px; font-size: 0.875rem;
transition: color 0.15s, background 0.15s;
}
.navbar-links a:hover { color: white; background: #334155; }
/* โโ Equal-height cards via flex: 1 โโ */
.card-row { display: flex; gap: 16px; }
.card {
flex: 1; /* each card takes equal share */
background: white;
border: 1px solid #e2e8f0;
border-radius: 12px;
padding: 20px;
display: flex;
flex-direction: column; /* stack internals vertically */
}
.card h3 { margin: 0 0 8px; font-size: 1rem; color: #0f172a; }
.card p { flex: 1; color: #64748b; font-size: 0.875rem; line-height: 1.6; margin: 0 0 16px; }
.card a {
display: inline-block;
background: #4f46e5; color: white;
padding: 8px 16px; border-radius: 6px;
text-decoration: none; font-size: 0.8rem; font-weight: 600;
align-self: flex-start; /* button doesn't stretch to full width */
margin-top: auto; /* pushes button to card bottom */
}
</style>
</head>
<body>
<div class="hero">
<h1>Centered with Flexbox</h1>
<p>flex-direction: column + align-items: center + justify-content: center</p>
</div>
<nav class="navbar">
<span class="navbar-brand">Brand</span>
<ul class="navbar-links">
<li><a href="#">Home</a></li>
<li><a href="#">About</a></li>
<li><a href="#">Contact</a></li>
</ul>
</nav>
<div class="card-row">
<div class="card">
<h3>Card A</h3>
<p>Short content.</p>
<a href="#">Learn more</a>
</div>
<div class="card">
<h3>Card B</h3>
<p>This card has much more content than the others to show that all cards reach the same height automatically thanks to Flexbox.</p>
<a href="#">Learn more</a>
</div>
<div class="card">
<h3>Card C</h3>
<p>Medium amount of content here in this card.</p>
<a href="#">Learn more</a>
</div>
</div>
</body>
</html>
How It Works
Step 1 โ display: flex Activates the Flex Context
Adding display: flex to a parent instantly makes all its direct children into flex items. They are placed along the main axis (horizontal by default) and stretch to fill the cross axis height by default via align-items: stretch.
Step 2 โ flex-direction: column Flips the Axes
In the hero section, flex-direction: column makes the vertical direction the main axis. Now justify-content: center centers vertically and align-items: center centers horizontally โ perfect centering with two properties and no absolute positioning.
Step 3 โ justify-content: space-between Creates the Navbar Split
With only two children in .navbar, justify-content: space-between places the brand against the left edge and the links against the right edge โ all remaining space falls between them. Adding more items distributes space evenly.
Step 4 โ flex: 1 Gives Each Card an Equal Share
Each card gets flex: 1 โ shorthand for flex-grow: 1; flex-shrink: 1; flex-basis: 0%. All three cards request equal priority for free space, so they always share the row width equally regardless of content length.
Step 5 โ margin-top: auto Pins Button to Card Bottom
Inside each card (itself a column flex container), the link gets margin-top: auto. This absorbs all surplus vertical space above the button, pinning it to the card’s bottom โ creating perfectly aligned CTAs across all cards regardless of how much text each card contains.
Real-World Example: App Shell Layout
/* app-shell.css */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html, body { height: 100%; }
.app-shell {
display: flex;
flex-direction: column;
min-height: 100vh;
font-family: system-ui, sans-serif;
}
/* Header โ fixed height, never shrinks */
.app-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 24px;
height: 60px;
background: #1e293b;
color: white;
flex-shrink: 0;
}
.header-actions { display: flex; align-items: center; gap: 12px; }
/* Body โ flex row (sidebar + main) */
.app-body {
display: flex;
flex: 1;
overflow: hidden;
}
/* Fixed-width sidebar */
.sidebar {
width: 240px;
flex-shrink: 0;
background: #f8fafc;
border-right: 1px solid #e2e8f0;
padding: 20px 0;
overflow-y: auto;
}
/* Main content fills remaining space */
.main-content {
flex: 1;
overflow-y: auto;
padding: 32px;
background: white;
}
/* Footer โ fixed height, never shrinks */
.app-footer {
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px 24px;
background: #f1f5f9;
border-top: 1px solid #e2e8f0;
font-size: 0.8rem;
color: #64748b;
flex-shrink: 0;
}
Common Mistakes
Mistake 1 โ Confusing main and cross axis after direction change
โ Wrong โ expecting justify-content to center horizontally in a column layout:
.column {
display: flex;
flex-direction: column;
justify-content: center; /* centers VERTICALLY โ not horizontally */
}
โ Correct โ use align-items for horizontal centering in a column layout:
.column {
display: flex;
flex-direction: column;
align-items: center; /* centers horizontally */
justify-content: center; /* centers vertically */
}
Mistake 2 โ Using margin for item spacing instead of gap
โ Wrong โ margin on flex children creates uneven outer edges:
.flex-row { display: flex; }
.flex-row > * { margin: 0 12px; } /* first and last items have unwanted outer gap */
โ Correct โ gap applies only between items, never on outer edges:
.flex-row { display: flex; gap: 24px; }
Mistake 3 โ flex: 1 causing items to shrink below content width
โ Wrong โ long text overflows because flex item shrinks below min-content:
.item { flex: 1; } /* can shrink to 0 โ text overflows */
โ Correct โ add min-width: 0 with overflow handling:
.item { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
Quick Reference
| Property | Applies To | Common Values |
|---|---|---|
display: flex |
Container | Activates flex layout |
flex-direction |
Container | row (default), column, row-reverse, column-reverse |
justify-content |
Container | flex-start, center, space-between, space-evenly |
align-items |
Container | stretch, center, flex-start, flex-end, baseline |
gap |
Container | Any length โ replaces margin hacks |
flex: 1 |
Item | Grow + shrink equally from 0 basis |
align-self |
Item | Override align-items for one item |
margin-top: auto |
Item | Absorbs free space โ pins item to far edge |