Chapter 15: CSS Flexbox Layout — Complete Guide
The Flexible Box Layout Module (Flexbox) is the industry-standard solution for 1D web layouts. It handles item distribution, alignment, ordering, and responsive reflow automatically — eliminating the need for legacy float hacks. Mastering flexbox is essential for every modern web developer.
15.1 Understanding Flexbox Axes: Main Axis vs Cross Axis
Flexbox layout operates along two perpendicular axes. Every flexbox property targets one of these two axes:
| Axis | Direction (Default) | Properties That Control It | Changed By |
|---|---|---|---|
| Main Axis | Horizontal (left → right) | justify-content, flex-direction |
flex-direction: column rotates it vertically |
| Cross Axis | Vertical (top → bottom) | align-items, align-self, align-content |
Always perpendicular to main axis |
15.2 Flex Container Properties — Complete Reference
Container properties are applied to the parent element with display: flex. They control
the layout strategy for all child flex items:
| Property | Values | Description | Default |
|---|---|---|---|
display |
flex, inline-flex |
Activates flexbox context. inline-flex keeps the container inline. |
— |
flex-direction |
row, row-reverse, column, column-reverse |
Sets direction and orientation of the Main Axis. | row |
flex-wrap |
nowrap, wrap, wrap-reverse |
Controls whether items can wrap onto multiple lines. | nowrap |
flex-flow |
row wrap, column nowrap |
Shorthand combining flex-direction and flex-wrap. |
row nowrap |
justify-content |
flex-start, flex-end, center, space-between,
space-around, space-evenly
|
Distributes items along the Main Axis. | flex-start |
align-items |
stretch, flex-start, flex-end, center,
baseline
|
Aligns items along the Cross Axis for a single line. | stretch |
align-content |
flex-start, flex-end, center, space-between,
space-around, stretch
|
Aligns multiple lines when flex-wrap: wrap is active. Has no effect on
single-line containers. |
stretch |
gap |
16px, 1rem 2rem |
Sets row-gap and column-gap between flex items (no margins needed). | 0 |
<!DOCTYPE html>
<html>
<head>
<style>
*, *::before, *::after { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; background: #0f172a; color: #f8fafc; padding: 24px; margin: 0; }
h4 { color: #38bdf8; margin: 0 0 8px 0; font-size: 13px; }
/* flex-flow shorthand = flex-direction + flex-wrap */
.flex-container {
display: flex;
flex-flow: row wrap; /* shorthand for: flex-direction: row; flex-wrap: wrap; */
justify-content: space-between;
align-items: center;
gap: 12px 20px; /* row-gap: 12px, column-gap: 20px */
background: #1e293b;
border: 2px dashed #38bdf8;
border-radius: 12px;
padding: 20px;
}
.item {
background: rgba(99,102,241,0.25);
border: 2px solid #6366f1;
border-radius: 8px;
padding: 14px 20px;
font-weight: 700;
font-size: 13px;
color: #a5b4fc;
}
</style>
</head>
<body>
<h4>flex-flow: row wrap | justify-content: space-between | gap: 12px 20px</h4>
<div class="flex-container">
<div class="item">Item A</div>
<div class="item" style="border-color:#10b981;color:#34d399;background:rgba(16,185,129,0.25);">Item B</div>
<div class="item" style="border-color:#f59e0b;color:#fbbf24;background:rgba(245,158,11,0.25);">Item C</div>
<div class="item" style="border-color:#ec4899;color:#f472b6;background:rgba(236,72,153,0.25);">Item D</div>
</div>
</body>
</html>
15.3 flex-grow, flex-shrink & flex-basis — In-Depth
These three properties are the heart of flexbox's space distribution algorithm. Understanding them precisely unlocks fine-grained control over how items share available space:
The Flex Shorthand Formula
flex: <flex-grow> <flex-shrink> <flex-basis>Examples:
flex: 1 = grow:1 shrink:1 basis:0% | flex: 0 0 200px = fixed 200px, no
grow/shrink | flex: 2 1 auto = double growth rate
| Property | Default | What It Controls | Common Values |
|---|---|---|---|
flex-grow |
0 (don't grow) |
Ratio of extra empty space an item claims after all items reach their flex-basis size. |
0 = rigid, 1 = equal share, 2 = double share |
flex-shrink |
1 (can shrink) |
Ratio of space an item gives up when the container overflows. Set to 0 to prevent shrinking.
|
0 = never shrink, 1 = default shrink, 2 = shrinks twice as fast |
flex-basis |
auto |
Starting size of item before grow/shrink ratios are applied. Overrides width on main
axis. |
auto, 0, 150px, 30% |
flex (shorthand) |
0 1 auto |
Always use the shorthand! It sets smart defaults: flex: 1 → equally share all space. |
flex: 1, flex: 0 0 200px, flex: 2 |
<!DOCTYPE html>
<html>
<head>
<style>
*, *::before, *::after { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; background: #0f172a; color: #f8fafc; padding: 24px; margin: 0; display: flex; flex-direction: column; gap: 20px; }
h4 { color: #818cf8; margin: 0 0 6px; font-size: 13px; }
.label { font-size: 11px; color: #64748b; font-family: monospace; margin-bottom: 4px; }
.row { display: flex; gap: 8px; background: #1e293b; border-radius: 10px; padding: 12px; }
.box { border-radius: 8px; padding: 12px 8px; font-size: 11px; font-family: monospace; font-weight: bold; text-align: center; min-width: 0; }
/* Scenario 1: Equal grow */
.grow-1 { flex: 1; background: rgba(99,102,241,0.25); border: 2px solid #6366f1; color: #a5b4fc; }
/* Scenario 2: Unequal grow ratios */
.grow-ratio-1 { flex: 1; background: rgba(56,189,248,0.2); border: 2px solid #38bdf8; color: #7dd3fc; }
.grow-ratio-3 { flex: 3; background: rgba(16,185,129,0.2); border: 2px solid #10b981; color: #34d399; }
/* Scenario 3: Fixed + flexible mix */
.fixed { flex: 0 0 120px; background: rgba(245,158,11,0.2); border: 2px solid #f59e0b; color: #fbbf24; }
.flexible { flex: 1; background: rgba(236,72,153,0.2); border: 2px solid #ec4899; color: #f472b6; }
/* Scenario 4: No shrink */
.no-shrink { flex: 0 0 300px; background: rgba(239,68,68,0.2); border: 2px solid #ef4444; color: #fca5a5; }
</style>
</head>
<body>
<h4>flex-grow / flex-shrink / flex-basis Visualizer</h4>
<div>
<p class="label">Scenario 1: flex: 1 (all items share space equally)</p>
<div class="row">
<div class="box grow-1">flex: 1</div>
<div class="box grow-1">flex: 1</div>
<div class="box grow-1">flex: 1</div>
</div>
</div>
<div>
<p class="label">Scenario 2: flex: 1 vs flex: 3 (unequal ratios — middle item gets 3× space)</p>
<div class="row">
<div class="box grow-ratio-1">flex: 1</div>
<div class="box grow-ratio-3">flex: 3 (3× width)</div>
<div class="box grow-ratio-1">flex: 1</div>
</div>
</div>
<div>
<p class="label">Scenario 3: flex: 0 0 120px (fixed sidebar) + flex: 1 (flexible content)</p>
<div class="row">
<div class="box fixed">Sidebar<br/>flex: 0 0 120px</div>
<div class="box flexible">Main Content — fills all remaining space (flex: 1)</div>
</div>
</div>
<div>
<p class="label">Scenario 4: flex-shrink: 0 — item refuses to shrink below flex-basis</p>
<div class="row" style="overflow-x: auto;">
<div class="box no-shrink">flex: 0 0 300px<br/>shrink: 0 (never squishes)</div>
<div class="box grow-1" style="flex-basis: 300px;">flex: 0 0 300px<br/>default shrink: 1</div>
</div>
</div>
</body>
</html>
15.4 align-content vs align-items (Multi-Line Wrapping Behavior)
This is one of the most misunderstood areas of Flexbox. The two properties look similar but apply to very different scenarios:
| Property | Applies When | Controls | Key Difference |
|---|---|---|---|
align-items |
Always | Alignment of items within each line along the Cross Axis | Works with single AND multi-line containers |
align-content |
Only when flex-wrap: wrap AND multiple lines exist |
Distribution of the lines themselves within the container | Has zero effect when only one row/column exists |
<!DOCTYPE html>
<html>
<head>
<style>
*, *::before, *::after { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; background: #0f172a; color: #f8fafc; padding: 24px; margin: 0; display: flex; flex-direction: column; gap: 24px; }
h4 { color: #38bdf8; margin: 0 0 8px; }
.container {
display: flex;
flex-wrap: wrap; /* Enables multi-line wrapping */
gap: 8px;
background: #1e293b;
border: 2px dashed #3b82f6;
border-radius: 12px;
padding: 12px;
height: 200px; /* Fixed height so align-content has space to work */
}
.item {
background: rgba(99,102,241,0.3);
border: 2px solid #6366f1;
border-radius: 8px;
padding: 12px;
font-size: 12px;
font-weight: bold;
color: #a5b4fc;
width: 100px;
}
/* align-content distributes the rows */
.ac-space-between { align-content: space-between; }
.ac-center { align-content: center; }
</style>
</head>
<body>
<div>
<h4>align-content: space-between (rows pushed to top/bottom edges)</h4>
<div class="container ac-space-between">
<div class="item">Item 1</div>
<div class="item" style="border-color:#10b981;color:#34d399;background:rgba(16,185,129,0.3);">Item 2</div>
<div class="item" style="border-color:#f59e0b;color:#fbbf24;background:rgba(245,158,11,0.3);">Item 3</div>
<div class="item">Item 4</div>
<div class="item" style="border-color:#10b981;color:#34d399;background:rgba(16,185,129,0.3);">Item 5</div>
</div>
</div>
<div>
<h4>align-content: center (all rows centered vertically as a group)</h4>
<div class="container ac-center">
<div class="item">Item 1</div>
<div class="item" style="border-color:#10b981;color:#34d399;background:rgba(16,185,129,0.3);">Item 2</div>
<div class="item" style="border-color:#f59e0b;color:#fbbf24;background:rgba(245,158,11,0.3);">Item 3</div>
<div class="item">Item 4</div>
<div class="item" style="border-color:#10b981;color:#34d399;background:rgba(16,185,129,0.3);">Item 5</div>
</div>
</div>
</body>
</html>
15.5 Flex Item Properties (order, align-self, min-width)
Item-level properties override the container's defaults for individual flex children:
| Property | Values | Description | Default |
|---|---|---|---|
order |
Integer: -1, 0, 1, 2 |
Changes visual rendering order without modifying HTML. Lower values render first. | 0 |
align-self |
auto, flex-start, flex-end, center,
baseline, stretch
|
Overrides parent align-items for this specific item only. |
auto (inherits from parent) |
min-width / min-height |
0, auto, 200px |
Prevents flex items from shrinking below a minimum size. Setting min-width: 0 fixes text
overflow issues. |
auto |
<!DOCTYPE html>
<html>
<head>
<style>
*, *::before, *::after { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; background: #0f172a; color: #f8fafc; padding: 24px; margin: 0; }
h4 { color: #f59e0b; margin: 0 0 10px; }
.stage { display: flex; gap: 12px; height: 160px; background: #1e293b; border-radius: 10px; padding: 14px; align-items: flex-start; }
.item { background: rgba(99,102,241,0.25); border: 2px solid #6366f1; border-radius: 8px; padding: 12px; font-size: 12px; font-weight: bold; color: #a5b4fc; }
/* Order resequences the visual position (not HTML position) */
.order-minus1 { order: -1; background: rgba(245,158,11,0.25); border-color: #f59e0b; color: #fbbf24; }
/* align-self overrides parent align-items for individual item */
.self-end { align-self: flex-end; background: rgba(16,185,129,0.25); border-color: #10b981; color: #34d399; }
.self-center { align-self: center; background: rgba(236,72,153,0.25); border-color: #ec4899; color: #f472b6; }
.self-stretch{ align-self: stretch; background: rgba(139,92,246,0.25); border-color: #8b5cf6; color: #c4b5fd; }
</style>
</head>
<body>
<h4>order & align-self Demo</h4>
<p style="font-size:12px;color:#64748b;margin:0 0 10px;">HTML order: 1, 2, 3, 4. Visual order: 4 appears first (order:-1)</p>
<div class="stage">
<div class="item">1 · Default<br/>(align: flex-start)</div>
<div class="item self-end">2 · align-self:<br/>flex-end</div>
<div class="item self-center">3 · align-self:<br/>center</div>
<div class="item order-minus1">4 · order: -1<br/>(renders first!)</div>
</div>
</body>
</html>
15.6 Real-World Flexbox Patterns
Pattern 1 — Responsive Navigation Bar
A classic nav bar with logo on left, links in center/right using flexbox:
<!DOCTYPE html>
<html>
<head>
<style>
*, *::before, *::after { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; background: #0f172a; color: #f8fafc; margin: 0; }
/* Navbar container */
.navbar {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 24px;
height: 60px;
background: #1e293b;
border-bottom: 1px solid #334155;
}
.logo { font-weight: 800; font-size: 18px; color: #6366f1; letter-spacing: -0.5px; }
/* Nav links push to the right using margin-left: auto */
.nav-links { display: flex; gap: 24px; list-style: none; margin: 0; padding: 0; }
.nav-links a { color: #94a3b8; text-decoration: none; font-size: 14px; font-weight: 500; transition: color 0.2s; }
.nav-links a:hover { color: #f8fafc; }
/* CTA button: fixed size, no grow */
.btn-cta {
flex-shrink: 0; /* Never shrink */
background: #6366f1;
color: #fff;
border: none;
border-radius: 8px;
padding: 8px 18px;
font-size: 13px;
font-weight: 600;
cursor: pointer;
}
</style>
</head>
<body>
<nav class="navbar">
<div class="logo">AICodeLab</div>
<ul class="nav-links">
<li><a href="#">Tutorials</a></li>
<li><a href="#">Projects</a></li>
<li><a href="#">Blog</a></li>
</ul>
<button class="btn-cta">Get Started</button>
</nav>
</body>
</html>
Pattern 2 — Holy Grail Layout (Header, Sidebar, Main, Footer)
The "Holy Grail" layout has a header, two sidebars flanking main content, and a footer. Pure flexbox achieves this cleanly:
<!DOCTYPE html>
<html>
<head>
<style>
*, *::before, *::after { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; background: #0f172a; color: #f8fafc; margin: 0; padding: 20px; }
.label { font-size: 11px; font-family: monospace; color: #64748b; margin-bottom: 4px; }
.box { border-radius: 8px; padding: 14px; font-size: 13px; font-weight: bold; text-align: center; }
/* Outer page wrapper: vertical stack */
.page {
display: flex;
flex-direction: column;
gap: 8px;
height: 340px;
}
.header { background: rgba(99,102,241,0.3); border: 2px solid #6366f1; color: #a5b4fc; }
.footer { background: rgba(99,102,241,0.3); border: 2px solid #6366f1; color: #a5b4fc; }
/* Middle row: horizontal layout */
.middle {
display: flex;
flex: 1; /* grows to fill remaining vertical space */
gap: 8px;
}
.sidebar-left { flex: 0 0 140px; background: rgba(245,158,11,0.25); border: 2px solid #f59e0b; color: #fbbf24; }
.main-content { flex: 1; background: rgba(16,185,129,0.2); border: 2px solid #10b981; color: #34d399; }
.sidebar-right { flex: 0 0 120px; background: rgba(245,158,11,0.25); border: 2px solid #f59e0b; color: #fbbf24; }
</style>
</head>
<body>
<div class="page">
<div class="box header">Header (flex-direction: column — stacked)</div>
<div class="middle">
<div class="box sidebar-left">Left Sidebar<br/>flex: 0 0 140px</div>
<div class="box main-content">Main Content — flex: 1 (fills all remaining width)</div>
<div class="box sidebar-right">Right Sidebar<br/>flex: 0 0 120px</div>
</div>
<div class="box footer">Footer</div>
</div>
</body>
</html>
Pattern 3 — Auto-Responsive Card Grid (No Media Queries!)
Using flex-wrap: wrap + flex: 1 1 250px creates a grid that naturally reflows without any
@media rules:
<!DOCTYPE html>
<html>
<head>
<style>
*, *::before, *::after { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; background: #0f172a; color: #f8fafc; padding: 24px; margin: 0; }
h3 { color: #10b981; margin: 0 0 20px; }
.card-grid {
display: flex;
flex-wrap: wrap;
gap: 16px;
}
.card {
flex: 1 1 220px; /* grow: 1, shrink: 1, min-width: 220px */
background: #1e293b;
border: 1px solid #334155;
border-radius: 14px;
padding: 20px;
transition: transform 0.2s, box-shadow 0.2s;
}
.card:hover { transform: translateY(-4px); box-shadow: 0 12px 30px rgba(0,0,0,0.4); }
.card-icon { font-size: 28px; margin-bottom: 12px; }
.card h4 { margin: 0 0 8px; color: #f8fafc; font-size: 15px; }
.card p { margin: 0; font-size: 13px; color: #94a3b8; line-height: 1.6; }
</style>
</head>
<body>
<h3>Auto-Responsive Card Grid — No @media queries needed!</h3>
<div class="card-grid">
<div class="card"><div class="card-icon">🎨</div><h4>CSS Flexbox</h4><p>One-dimensional layout engine for rows and columns.</p></div>
<div class="card"><div class="card-icon">📐</div><h4>CSS Grid</h4><p>Two-dimensional layout engine with rows AND columns.</p></div>
<div class="card"><div class="card-icon">📱</div><h4>Responsive Design</h4><p>Adapts to any screen size with media queries.</p></div>
<div class="card"><div class="card-icon">⚡</div><h4>Performance</h4><p>GPU-accelerated transforms for smooth animations.</p></div>
</div>
</body>
</html>
15.7 Common Flexbox Gotchas & Solutions
| Problem | Cause | Fix |
|---|---|---|
| Text overflows flex item and breaks layout | Default min-width: auto prevents item from shrinking below content size |
Add min-width: 0 to the flex item |
align-content has no effect |
Container has only one flex line (no wrapping, or not enough items to wrap) | Ensure flex-wrap: wrap is set AND items actually wrap |
| Items don't fill full height of container | Container has no defined height, or items use align-items: flex-start |
Add align-items: stretch (default) or set explicit height on container |
| Image inside flex item distorts | Image is also a flex item and gets stretched by align-items: stretch |
Add align-self: flex-start to the image, or set object-fit: cover |
| Last row of wrapped items stretches to fill width | justify-content: space-between spreads items across last row unevenly |
Add an empty <div> spacer element, or switch to CSS Grid for card grids |
gap not working |
Using older browsers that don't support gap in flexbox |
Use margin on items as fallback, or use column-gap / row-gap
explicitly |
15.8 Flex Container Properties — Concise Reference
A concise look at applying justify-content and align-items to center and distribute flex
items:
.item {
background: rgba(99,102,241,0.25);
border: 2px solid #6366f1;
border-radius: 8px;
padding: 12px 18px;
font-weight: 700; font-size: 13px; color: #a5b4fc;
}
<!-- justify-content: space-between & align-items: center demo -->
<div class="flex-stage">
<div class="item">Flex Item 1</div>
<div class="item" style="border-color:#10b981;color:#34d399;background:rgba(16,185,129,0.25);">Flex Item 2</div>
<div class="item" style="border-color:#f59e0b;color:#fbbf24;background:rgba(245,158,11,0.25);">Flex Item 3</div>
</div>
15.9 Flex Item Mechanics (flex-grow, flex-shrink, flex-basis)
Flex item properties control how individual items expand or shrink to fill remaining space in the container.
| Item Property | Syntax & Default | Behavior Description |
|---|---|---|
flex-grow |
0 (Default), 1, 2 |
Proportional factor to expand item into available empty space. |
flex-shrink |
1 (Default), 0 |
Proportional factor to shrink item when container is constrained. Set 0 to prevent shrinking!
|
flex-basis |
auto, 200px |
Initial size of item before grow/shrink factors are calculated. |
flex (Shorthand) |
flex: 1; (grow:1 shrink:1 basis:0%) |
Recommended shorthand combining grow, shrink, and basis. |
<!DOCTYPE html>
<html>
<head>
<style>
*, *::before, *::after { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; background: #0f172a; color: #f8fafc; padding: 24px; margin: 0; }
h3 { margin-top: 0; color: #818cf8; }
.grow-stage { display: flex; gap: 12px; background: #1e293b; border-radius: 10px; padding: 14px; }
.box { background: rgba(99,102,241,0.2); border: 2px solid #6366f1; border-radius: 8px; padding: 12px; font-size: 12px; font-family: monospace; color: #a5b4fc; text-align: center; }
.grow-1 { flex-grow: 1; }
.grow-2 { flex-grow: 2; background: rgba(16,185,129,0.2); border-color: #10b981; color: #34d399; }
</style>
</head>
<body>
<h3>flex-grow Proportional Expansion Demo</h3>
<p style="font-size:12px;color:#64748b;">Box 2 has flex-grow: 2, so it receives double the remaining empty space compared to flex-grow: 1 boxes:</p>
<div class="grow-stage">
<div class="box grow-1">flex-grow: 1</div>
<div class="box grow-2">flex-grow: 2 (Double Space)</div>
<div class="box grow-1">flex-grow: 1</div>
</div>
</body>
</html>
15.10 Item Ordering & Self Alignment (order & align-self)
The order property changes visual rendering order without modifying HTML markup, while
align-self overrides the parent's align-items for an individual item.
<!DOCTYPE html>
<html>
<head>
<style>
*, *::before, *::after { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; background: #0f172a; color: #f8fafc; padding: 24px; margin: 0; }
h3 { margin-top: 0; color: #f59e0b; }
.stage { display: flex; gap: 12px; height: 140px; background: #1e293b; border-radius: 10px; padding: 14px; align-items: flex-start; }
.item { background: rgba(99,102,241,0.25); border: 2px solid #6366f1; border-radius: 8px; padding: 12px; font-size: 12px; font-weight: bold; }
.order-first { order: -1; background: rgba(245,158,11,0.25); border-color: #f59e0b; color: #fbbf24; }
.self-end { align-self: flex-end; background: rgba(16,185,129,0.25); border-color: #10b981; color: #34d399; }
</style>
</head>
<body>
<h3>order: -1 & align-self: flex-end Demo</h3>
<div class="stage">
<div class="item">Item 1 (HTML First)</div>
<div class="item self-end">Item 2 (align-self: flex-end)</div>
<div class="item order-first">Item 3 (order: -1 — Rendered First!)</div>
</div>
</body>
</html>
15.11 Responsive Flexbox Layout Patterns
Combining flex-wrap: wrap with flex: 1 1 200px creates card grids that automatically reflow
on small screens without hardcoded media query breakpoints!
<!DOCTYPE html>
<html>
<head>
<style>
*, *::before, *::after { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; background: #0f172a; color: #f8fafc; padding: 24px; margin: 0; }
h3 { margin-top: 0; color: #10b981; }
/* Responsive Wrapping Card Layout */
.card-grid {
display: flex;
flex-wrap: wrap;
gap: 16px;
}
.card {
flex: 1 1 180px; /* grow: 1, shrink: 1, basis: 180px */
background: #1e293b;
border: 1px solid #334155;
border-radius: 12px;
padding: 16px;
}
.card h4 { margin-top: 0; color: #38bdf8; }
.card p { font-size: 13px; color: #cbd5e1; margin: 0; }
</style>
</head>
<body>
<h3>Responsive Flex Wrapping Cards (flex: 1 1 180px)</h3>
<p style="font-size:12px;color:#64748b;">Resize browser width to see cards automatically wrap into multiple rows!</p>
<div class="card-grid">
<div class="card"><h4>Card 1</h4><p>Flex item with flex-basis: 180px.</p></div>
<div class="card"><h4>Card 2</h4><p>Fills available row width smoothly.</p></div>
<div class="card"><h4>Card 3</h4><p>Wraps to next row on narrow screens.</p></div>
</div>
</body>
</html>
15.12 Interactive Sandbox — Full Flexbox Playground
Experiment with the Holy Grail layout, flex-grow ratios, and the card grid pattern in the live playground below: