CSS Flexbox & Grid: The Layout Guide I Wish I Had (2026)
Stop fighting with CSS layouts. Once you understand these two systems, everything clicks.
The Big Picture
Before 2017: Floats, tables, absolute positioning → painful
2017+: Flexbox + Grid → layout is actually easy now
When to use which:
→ Flexbox: ONE-dimensional layout (row OR column)
→ Grid: TWO-dimensional layout (rows AND columns)
Most layouts use BOTH together.
Flexbox Fundamentals
Core Concepts
.container {
display: flex;
/* Main axis direction */
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 */
/* Wrapping behavior */
flex-wrap: nowrap; /* Default: don't wrap, shrink items */
flex-wrap: wrap; /* Wrap to next line when needed */
flex-wrap: wrap-reverse; /* Wrap upward */
/* Shorthand for direction + wrap */
flex-flow: row wrap;
/* Main axis alignment */
justify-content: flex-start; /* Default: pack to start */
justify-content: center; /* Center horizontally */
justify-content: flex-end; /* Pack to end */
justify-content: space-between; /* Equal space BETWEEN items */
justify-content: space-around; /* Equal space AROUND each item */
justify-content: space-evenly; /* Equal space everywhere */
/* Cross axis alignment */
align-items: stretch; /* Default: stretch to fill container */
align-items: flex-start; /* Align to cross-axis start */
align-items: center; /* Center vertically */
align-items: flex-end; /* Align to cross-axis end */
align-items: baseline; /* Align text baselines */
/* Gap between items */
gap: 16px; /* Row and column gap */
row-gap: 8px;
column-gap: 16px;
}
.item {
/* Item-level control */
flex-grow: 0; /* Default: don't grow to fill space */
flex-shrink: 1; /* Default: can shrink if needed */
flex-basis: auto; /* Default initial size */
/* Shorthand: grow shrink basis */
flex: 1; /* grow=1, shrink=1, basis=0% → fills available space */
flex: 0 0 auto; /* Don't grow or shrink (fixed size) */
flex: 1 1 200px; /* Grow, shrink, start at 200px */
/* Override container's align-items for this item */
align-self: center;
}
Practical Flexbox Patterns
<!-- Pattern 1: Center anything (the #1 use case) -->
<div class="center">
<div class="content">Perfectly centered</div>
</div>
<style>
.center {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
</style>
<!-- Pattern 2: Navigation bar -->
<nav class="navbar">
<a href="/" class="logo">Brand</a>
<div class="nav-links">
<a href="/products">Products</a>
<a href="/about">About</a>
<a href="/contact">Contact</a>
</div>
<button class="cta">Sign Up</button>
</nav>
<style>
.navbar {
display: flex;
align-items: center;
justify-content: space-between;
padding: 1rem 2rem;
}
.nav-links { display: flex; gap: 2rem; }
.cta { margin-left: auto; } /* Push to right */
</style>
<!-- Pattern 3: Card grid with auto-sizing -->
<div class="card-grid">
<div class="card">Short content</div>
<div class="card">Medium length content here</div>
<div class="card">This card has much more content than the others</div>
</div>
<style>
.card-grid {
display: flex;
flex-wrap: wrap;
gap: 1rem;
}
.card {
flex: 1 1 300px; /* Grow, shrink, base 300px */
/* Cards auto-size: min 300px, share remaining equally */
}
</style>
<!-- Pattern 4: Sticky footer -->
<body class="app-layout">
<header>Header</header>
<main>Content that pushes footer down</main>
<footer>Footer always at bottom</footer>
</body>
<style>
.app-layout {
display: flex;
flex-direction: column;
min-height: 100vh;
}
main { flex: 1; } /* Takes all available space */
</style>
<!-- Pattern 5: Media object (avatar + text) -->
<div class="media">
<img src="avatar.jpg" class="media-img" alt="">
<div class="media-body">
<h4>Name</h4>
<p>Description text goes here</p>
</div>
</div>
<style>
.media { display: flex; align-items: flex-start; gap: 1rem; }
.media-img { flex-shrink: 0; width: 48px; height: 48px; border-radius: 50%; }
.media-body { flex: 1; min-width: 0; } /* min-width:0 enables text truncation */
</style>
CSS Grid Fundamentals
Core Concepts
.container {
display: grid;
/* Define columns */
grid-template-columns: 200px 1fr 200px; /* 3 fixed/flexible columns */
grid-template-columns: repeat(3, 1fr); /* 3 equal columns */
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); /* Responsive! */
grid-template-columns: 200px repeat(2, 1fr) 100px; /* Mixed sizes */
/* Define rows */
grid-template-rows: auto 1fr auto; /* Header, content, footer height */
grid-template-rows: masonry; /* Masonry layout (experimental but useful) */
/* Shorthand for columns + rows */
grid-template:
"header header header" 60px
"sidebar main ads" 1fr
"footer footer footer" 40px
/ 200px 1fr 200px;
/* Gap */
gap: 20px;
row-gap: 10px;
column-gap: 15px;
/* Justify (column axis = horizontal) */
justify-items: start; /* Default: stretch */
justify-content: center; /* When total grid size < container */
/* Align (row axis = vertical) */
align-items: center;
align-content: center; /* When total grid size < container */
/* Place items in the grid */
place-items: center; /* Shorthand: align-items + justify-items */
}
.item {
/* Position items explicitly */
grid-column: 1 / -1; /* Span from first to last column line */
grid-column: 1 / span 2; /* Start at col 1, span 2 columns */
grid-row: 2 / 3;
/* Shorthand */
grid-area: 2 / 1 / 3 / 2; /* row-start / col-start / row-end / col-end */
/* Or use named areas from grid-template */
grid-area: header;
/* Override alignment for this item */
justify-self: center;
align-self: start;
}
Practical Grid Patterns
<!-- Pattern 1: Holy Grail Layout (header + 3-col + footer) -->
<div class="holy-grail">
<header>Header</header>
<nav>Sidebar Nav</nav>
<main>Main Content Area</main>
<aside>Ads / Extras</aside>
<footer>Footer</footer>
</div>
<style>
.holy-grail {
display: grid;
grid-template:
"hd hd hd" auto
"nav main aside" 1fr
"ft ft ft" auto
/ 200px 1fr 200px;
min-height: 100vh;
gap: 1rem;
}
header { grid-area: hd; }
nav { grid-area: nav; }
main { grid-area: main; }
aside { grid-area: aside; }
footer { grid-area: ft; }
/* Responsive: collapse to single column on mobile */
@media (max-width: 768px) {
.holy-grail {
grid-template:
"hd" auto
"nav" auto
"main" 1fr
"aside" auto
"ft" auto
/ 1fr;
}
}
</style>
<!-- Pattern 2: Responsive Card Grid -->
<div class="grid-cards">
<div class="card">Card 1</div>
<div class="card">Card 2</div>
<div class="card">Card 3</div>
<div class="card">Card 4</div>
<div class="card">Card 5</div>
<div class="card">Card 6</div>
</div>
<style>
.grid-cards {
display: grid;
/* Auto-fill: creates as many 250px+ columns as will fit */
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 1.5rem;
}
/* No media query needed! Columns adjust automatically */
/* Wide screen: 4 columns → Medium: 3 → Tablet: 2 → Phone: 1 */
</style>
<!-- Pattern 3: Dashboard Grid -->
<div class="dashboard">
<div class="widget widget-wide">Chart (spans 2 cols)</div>
<div class="widget">Stats</div>
<div class="widget">Activity</div>
<div class="widget widget-tall">Table (spans 2 rows)</div>
<div class="widget">Alerts</div>
</div>
<style>
.dashboard {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: 200px;
gap: 1rem;
}
.widget { background: white; border-radius: 8px; padding: 1rem; }
.widget-wide { grid-column: span 2; }
.widget-tall { grid-row: span 2; }
</style>
<!-- Pattern 4: Feature comparison table -->
<div class="comparison-grid">
<div class="cell header">Feature</div>
<div class="cell header">Free</div>
<div class="cell header">Pro</div>
<div class="cell">Storage</div>
<div class="cell">1 GB</div>
<div class="cell">Unlimited</div>
<div class="cell">API Access</div>
<div class="cell">❌</div>
<div class="cell">✅</div>
</div>
<style>
.comparison-grid {
display: grid;
grid-template-columns: 2fr 1fr 1fr;
gap: 1px;
background: #e0e0e0; /* Creates borders via gaps */
border: 1px solid #e0e0e0;
}
.cell { background: white; padding: 0.75rem; }
.cell.header { font-weight: bold; background: #f5f5f5; }
</style>
Flexbox vs Grid: Decision Guide
Choose FLEXBOX when:
✓ Laying out items in ONE direction (row OR column)
✓ Distributing space between items (justify-content)
✓ Aligning items vertically within a container
✓ Content-driven sizing (items size based on their content)
✓ Navigation bars, card rows, form inputs, centering
Choose GRID when:
✓ TWO-dimensional layout (rows AND columns needed)
✓ Overlapping elements (explicit placement)
✓ Complex page-level layouts (holy grail, dashboard)
✓ Items need to span multiple rows/columns
✓ Precise control over both axes simultaneously
Common combo: Grid for PAGE layout → Flexbox for COMPONENT layout
Modern Tricks You Might Not Know
/* Subgrid: Child grid inherits parent's track definitions */
.card-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
}
.card {
display: grid;
grid-template-rows: subgrid; /* Inherits row tracks from parent! */
gap: inherit; /* Inherits the same gap */
}
/* Container queries: Style based on container size, not viewport! */
.card-container {
container-type: inline-name;
container-name: card;
}
@container card (min-width: 400px) {
.card-inner { flex-direction: row; } /* Horizontal layout when wide enough */
}
@container card (max-width: 399px) {
.card-inner { flex-direction: column; } /* Stack vertically when narrow */
}
/* Logical properties (for RTL/internationalization support) */
.element {
/* Instead of left/right/top/bottom: */
margin-inline-start: 1rem; /* = margin-left in LTR, margin-right in RTL */
margin-block-end: 0.5rem; /* = margin-bottom */
inset-inline: 0; /* = left: 0; right: 0; */
/* For flex/grid: */
justify-content: flex-start; /* Works correctly in both directions */
}
/* aspect-ratio: Maintain proportions without padding hack */
.avatar {
width: 100%;
aspect-ratio: 1 / 1; /* Perfect square */
object-fit: cover;
}
.video-thumbnail {
aspect-ratio: 16 / 9;
object-fit: cover;
}
/* gap works with flexbox too! (not just grid) */
.form-row {
display: flex;
gap: 1rem; /* No more negative margin hacks! */
}
/* :has() selector — the "parent selector" we've been waiting for */
fieldset:has(:invalid) {
border-color: red; /* Style parent based on children! */
}
.card:has(.featured-badge) {
border: 2px solid gold;
}
Debugging Layout Issues
/* Quick debug: visualize your grid/flex structure */
.debug-grid {
outline: 1px solid red; /* Shows element boundaries */
}
/* Or use browser DevTools: Inspect → Layout panel */
/* Common issues and fixes: */
/* Issue: Items not centering? */
/* Fix: Make sure container has a defined height/min-height */
.center-container {
display: flex;
justify-content: center;
align-items: center;
min-height: 400px; /* ← This is often missing! */
}
/* Issue: Grid items not respecting grid-template? */
/* Fix: Check if implicit grid is being created by extra items */
.grid {
display: grid;
grid-template-columns: 1fr 1fr;
/* If you have 5 items, the 5th one creates an IMPLICIT new row */
grid-auto-columns: 200px; /* Control implicit column sizes */
grid-auto-rows: 100px; /* Control implicit row sizes */
}
/* Issue: Overflow on flex items? */
/* Fix: Allow shrinking or set min-width: 0 */
.flex-item {
flex: 1;
min-width: 0; /* Allows content to shrink below content size */
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* Issue: Gap not working? */
/* Fix: Gap doesn't work between margin:auto pushed items */
/* Use gap with flexbox, avoid combining with margin: auto on children */
What CSS layout problem took you longest to solve?
Follow @armorbreak for more practical developer guides.
Top comments (0)