Knowing the individual Flexbox properties is valuable; knowing which combination solves a specific layout problem is what makes you productive. In this lesson you will work through the most common real-world Flexbox patterns โ the holy grail layout, responsive navigation, media objects, and card decks with pinned footers โ understanding exactly why each property is chosen.
Most Common Flexbox Patterns
| Pattern | Key Properties | Typical Use Case |
|---|---|---|
| Perfect center | align-items: center; justify-content: center; |
Hero sections, modals, empty states |
| Sidebar + main | flex: 0 0 Npx sidebar, flex: 1 main |
Dashboard, docs, admin panels |
| Navbar split | justify-content: space-between or margin-left: auto |
Site header navigation |
| Media object | display: flex; gap: Npx; align-items: flex-start; |
Comments, notifications, list items |
| Pinned footer card | Column flex on card + margin-top: auto on footer |
Pricing cards, product tiles |
| Sticky header / footer in scroll | flex-shrink: 0 on header/footer, flex: 1; overflow-y: auto on body |
Chat windows, app shells |
Holy Grail Layout Properties
| Region | flex Value | Reason |
|---|---|---|
| Header | flex-shrink: 0 |
Never shrinks โ always full height |
| Left sidebar | flex: 0 0 200px |
Fixed width โ never grows or shrinks |
| Main content | flex: 1 |
Takes all remaining horizontal space |
| Right sidebar | flex: 0 0 180px |
Fixed width โ never grows or shrinks |
| Footer | flex-shrink: 0 |
Never shrinks โ always visible |
Media Object Variants
| Variant | Key Difference | Property Used |
|---|---|---|
| Standard | Image left, text right | flex-direction: row (default) |
| Reversed | Text left, image right | flex-direction: row-reverse |
| Stacked (mobile) | Image above text | flex-direction: column at narrow viewport |
| Top-aligned | Image doesn’t stretch to text height | align-items: flex-start |
display: flex, gap, align-items: flex-start, and flex-shrink: 0 on the image โ replacing table-based hacks that dominated for years.flex-shrink: 0, and give the message list flex: 1; overflow-y: auto. The browser handles the rest.display: flex creates a new formatting context. If a pattern can be achieved with a single flex container, don’t split it into two โ simpler CSS is easier to maintain, debug, and understand.Basic Example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Common Flexbox Patterns</title>
<style>
*, *::before, *::after { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; padding: 32px; background: #f8fafc; margin: 0; }
section { margin-bottom: 40px; }
h2 { font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.06em;
color: #64748b; margin: 0 0 12px; }
/* โโ 1. Perfect center โโ */
.center-demo {
display: flex;
align-items: center;
justify-content: center;
height: 140px;
background: linear-gradient(135deg, #4f46e5, #7c3aed);
border-radius: 12px;
color: white;
font-weight: 700;
font-size: 1.1rem;
}
/* โโ 2. Media object โโ */
.media {
display: flex;
gap: 16px;
align-items: flex-start;
background: white;
border: 1px solid #e2e8f0;
border-radius: 12px;
padding: 20px;
margin-bottom: 12px;
}
.media-img {
width: 56px;
height: 56px;
border-radius: 50%;
background: #ede9fe;
color: #4f46e5;
font-weight: 700;
font-size: 1.1rem;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0; /* never shrinks */
}
.media-body h3 { margin: 0 0 4px; font-size: 0.95rem; color: #0f172a; }
.media-body p { margin: 0; font-size: 0.875rem; color: #64748b; line-height: 1.5; }
/* โโ 3. Card with pinned footer โโ */
.card-deck { display: flex; gap: 16px; }
.pricing-card {
flex: 1;
display: flex;
flex-direction: column;
background: white;
border: 1px solid #e2e8f0;
border-radius: 16px;
padding: 24px;
}
.pricing-card .card-name { font-weight: 700; font-size: 0.9rem; color: #4f46e5; margin: 0 0 8px; }
.pricing-card .card-price { font-size: 2rem; font-weight: 800; color: #0f172a; margin: 0 0 16px; }
.pricing-card .card-price span { font-size: 1rem; font-weight: 400; color: #64748b; }
.pricing-card ul { list-style: none; padding: 0; margin: 0; font-size: 0.875rem; color: #475569; flex: 1; }
.pricing-card ul li { padding: 6px 0; border-bottom: 1px solid #f1f5f9; }
.pricing-card ul li::before { content: "โ "; color: #10b981; font-weight: 700; }
.pricing-card .card-cta {
display: block;
margin-top: auto; /* pinned to bottom */
padding-top: 20px;
text-align: center;
}
.pricing-card .card-cta a {
display: block;
padding: 12px;
background: #4f46e5;
color: white;
text-decoration: none;
border-radius: 8px;
font-weight: 600;
font-size: 0.9rem;
}
/* โโ 4. Chat window โโ */
.chat-window {
display: flex;
flex-direction: column;
height: 280px;
background: white;
border: 1px solid #e2e8f0;
border-radius: 12px;
overflow: hidden;
}
.chat-header {
display: flex;
align-items: center;
gap: 10px;
padding: 12px 16px;
background: #1e293b;
color: white;
font-size: 0.9rem;
font-weight: 600;
flex-shrink: 0; /* never shrinks */
}
.chat-messages {
flex: 1; /* fills remaining space */
overflow-y: auto;
padding: 16px;
display: flex;
flex-direction: column;
gap: 10px;
}
.msg { font-size: 0.85rem; padding: 8px 12px; border-radius: 8px; max-width: 80%; }
.msg-in { background: #f1f5f9; align-self: flex-start; }
.msg-out { background: #4f46e5; color: white; align-self: flex-end; }
.chat-input {
display: flex;
gap: 8px;
padding: 12px 16px;
border-top: 1px solid #e2e8f0;
flex-shrink: 0; /* never shrinks */
}
.chat-input input {
flex: 1;
border: 1px solid #e2e8f0;
border-radius: 6px;
padding: 8px 12px;
font-size: 0.875rem;
font-family: system-ui, sans-serif;
}
.chat-input button {
background: #4f46e5; color: white; border: none;
border-radius: 6px; padding: 8px 16px;
font-size: 0.8rem; cursor: pointer; font-weight: 600;
}
</style>
</head>
<body>
<section>
<h2>1 โ Perfect Center</h2>
<div class="center-demo">Perfectly Centered Content</div>
</section>
<section>
<h2>2 โ Media Object</h2>
<div class="media">
<div class="media-img">AR</div>
<div class="media-body">
<h3>Alex Rivera <small style="color:#94a3b8;font-weight:400">2 hours ago</small></h3>
<p>Great article! The section on align-self was especially helpful for understanding how to build toolbars with mixed alignment requirements.</p>
</div>
</div>
</section>
<section>
<h2>3 โ Pricing Cards with Pinned CTA</h2>
<div class="card-deck">
<div class="pricing-card">
<p class="card-name">Starter</p>
<p class="card-price">$0 <span>/ month</span></p>
<ul><li>5 projects</li><li>1GB storage</li></ul>
<div class="card-cta"><a href="#">Get started</a></div>
</div>
<div class="pricing-card">
<p class="card-name">Pro</p>
<p class="card-price">$19 <span>/ month</span></p>
<ul><li>Unlimited projects</li><li>20GB storage</li><li>Priority support</li><li>Analytics</li></ul>
<div class="card-cta"><a href="#">Upgrade now</a></div>
</div>
<div class="pricing-card">
<p class="card-name">Enterprise</p>
<p class="card-price">$49 <span>/ month</span></p>
<ul><li>Unlimited everything</li><li>100GB storage</li><li>24/7 support</li></ul>
<div class="card-cta"><a href="#">Contact sales</a></div>
</div>
</div>
</section>
<section>
<h2>4 โ Chat Window (scrollable middle, fixed header and input)</h2>
<div class="chat-window">
<div class="chat-header">
<div style="width:28px;height:28px;border-radius:50%;background:#4f46e5;display:flex;align-items:center;justify-content:center;font-size:0.75rem;">JD</div>
Jane Doe โ Online
</div>
<div class="chat-messages">
<div class="msg msg-in">Hey! Did you see the new Flexbox lesson?</div>
<div class="msg msg-out">Yes! The alignment section was super clear.</div>
<div class="msg msg-in">The margin-left: auto trick blew my mind.</div>
<div class="msg msg-out">Same! I had been using spacer divs for that ๐
</div>
<div class="msg msg-in">Now I need to go rewrite half my nav bars.</div>
</div>
<div class="chat-input">
<input type="text" placeholder="Type a message...">
<button>Send</button>
</div>
</div>
</section>
</body>
</html>
How It Works
Step 1 โ Media Object Uses align-items: flex-start
Setting align-items: flex-start prevents the avatar from stretching to the full height of the text block. The avatar stays at its natural 56px height regardless of how long the text is โ the fundamental media object pattern.
Step 2 โ flex-shrink: 0 Protects the Avatar Size
In a narrow container, flex items shrink by default. The avatar with flex-shrink: 0 always stays 56ร56px. Without it the avatar would squish โ a common Flexbox gotcha with fixed-size images and icons.
Step 3 โ Column Flex + margin-top: auto Pins the CTA
Each pricing card is a column flex container. The feature list gets flex: 1 to absorb height differences. The CTA div gets margin-top: auto โ this pushes it to the card’s absolute bottom regardless of feature count, aligning all three CTAs perfectly.
Step 4 โ Chat Window Uses Three-Layer Column Flex
The chat shell is a column flex container with fixed height. The header and input bar both have flex-shrink: 0 so they never collapse. The message list has flex: 1 so it claims all remaining height, plus overflow-y: auto to enable scrolling when messages overflow.
Step 5 โ Column Flex on Messages Creates Bubble Alignment
The message list is itself a column flex container with gap: 10px. Sent messages have align-self: flex-end and received messages have align-self: flex-start โ the two-line solution for the classic chat bubble layout.
Real-World Example: Holy Grail Layout
/* holy-grail.css */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html, body { height: 100%; }
.page {
display: flex;
flex-direction: column;
min-height: 100vh;
font-family: system-ui, sans-serif;
}
.page-header {
background: #1e293b;
color: white;
padding: 0 24px;
height: 60px;
display: flex;
align-items: center;
justify-content: space-between;
flex-shrink: 0;
}
.page-body {
display: flex;
flex: 1;
overflow: hidden;
}
.page-left-sidebar {
width: 220px;
flex-shrink: 0;
background: #f8fafc;
border-right: 1px solid #e2e8f0;
overflow-y: auto;
padding: 24px 0;
}
.page-main {
flex: 1;
overflow-y: auto;
padding: 32px;
background: white;
}
.page-right-sidebar {
width: 200px;
flex-shrink: 0;
background: #f8fafc;
border-left: 1px solid #e2e8f0;
overflow-y: auto;
padding: 24px 16px;
}
.page-footer {
background: #f1f5f9;
border-top: 1px solid #e2e8f0;
padding: 12px 24px;
font-size: 0.8rem;
color: #64748b;
display: flex;
justify-content: space-between;
align-items: center;
flex-shrink: 0;
}
Common Mistakes
Mistake 1 โ Not setting flex-shrink: 0 on fixed UI chrome
โ Wrong โ header collapses when content is long:
.header { height: 60px; } /* shrinks in a flex container when space is tight */
โ Correct โ explicitly prevent shrinking:
.header { height: 60px; flex-shrink: 0; }
Mistake 2 โ Scrollable area without flex: 1
โ Wrong โ message list does not fill the available space:
.messages { overflow-y: auto; } /* no flex-grow โ area doesn't expand */
โ Correct โ flex: 1 makes the list fill remaining height:
.messages { flex: 1; overflow-y: auto; }
Mistake 3 โ Pinning CTA with padding instead of margin-top: auto
โ Wrong โ CTA appears at different heights across cards based on content:
.card { display: flex; flex-direction: column; }
.cta { padding-top: 20px; } /* does not actually pin to bottom */
โ Correct โ margin-top: auto absorbs all free space above:
.cta { margin-top: auto; padding-top: 20px; }
Quick Reference
| Pattern | CSS Technique | Key Property |
|---|---|---|
| Perfect center | Container: flex, align-items+justify-content: center | Both axes centered |
| Media object | flex row + gap + align-items: flex-start + flex-shrink: 0 on image | flex-shrink: 0 |
| Pinned CTA | Column flex card + flex: 1 on body + margin-top: auto on CTA | margin-top: auto |
| Scrollable middle | Column flex shell + flex-shrink: 0 on header/footer + flex: 1 + overflow-y: auto on body | flex: 1 + overflow |
| Navbar split | justify-content: space-between or margin-left: auto | margin-left: auto |
| Holy grail | Column shell, row body, fixed sidebars (flex: 0 0 Npx), fluid main (flex: 1) | flex: 0 0 Npx |