The Two Layout Powerhouses of Modern CSS
Every CSS layout decision you make boils down to one fundamental question: am I laying things out in one dimension or two dimensions? Flexbox handles rows or columns. Grid handles rows and columns simultaneously. That one-sentence distinction sounds simple, but the real skill is knowing exactly when to reach for which tool — and how to combine them to build any layout you can imagine.
This guide covers both systems in full depth, rebuilds real-world layouts from scratch, and gives you a decision framework you can use on every project going forward.
Flexbox Deep Dive
Flexbox (Flexible Box Layout) distributes space along a single axis. Every flexbox layout has a main axis (the direction items flow) and a cross axis (perpendicular to the main axis). All alignment properties reference these axes, not "horizontal" or "vertical."
Main Axis vs Cross Axis
When flex-direction: row (the default), the main axis is horizontal and the cross axis is vertical. When flex-direction: column, they swap. This is the single most important thing to understand about Flexbox — every alignment property is relative to these axes.
/* Main axis = horizontal, Cross axis = vertical */
.container-row {
display: flex;
flex-direction: row; /* default — items flow left to right */
justify-content: center; /* centers items along MAIN axis (horizontal) */
align-items: center; /* centers items along CROSS axis (vertical) */
}
/* Main axis = vertical, Cross axis = horizontal */
.container-column {
display: flex;
flex-direction: column; /* items flow top to bottom */
justify-content: center; /* centers items along MAIN axis (vertical) */
align-items: center; /* centers items along CROSS axis (horizontal) */
}
justify-content — Main Axis Alignment
.container {
display: flex;
/* Distributes items along the main axis */
justify-content: flex-start; /* pack items to start (default) */
justify-content: flex-end; /* pack items to end */
justify-content: center; /* center items */
justify-content: space-between; /* equal space BETWEEN items, none at edges */
justify-content: space-around; /* equal space around each item */
justify-content: space-evenly; /* truly equal space everywhere */
}
align-items vs align-self — Cross Axis Alignment
.container {
display: flex;
align-items: stretch; /* default — items stretch to fill cross axis */
align-items: flex-start; /* items align to start of cross axis */
align-items: flex-end; /* items align to end of cross axis */
align-items: center; /* items centered on cross axis */
align-items: baseline; /* items align by text baseline */
}
/* Override alignment for a single item */
.special-item {
align-self: flex-end; /* This item goes to the end while others stay centered */
}
flex-grow, flex-shrink, flex-basis — The Flex Trinity
These three properties control how flex items grow, shrink, and set their initial size. The shorthand flex is almost always better than setting them individually.
/* flex: grow shrink basis */
.item-fixed {
flex: 0 0 200px; /* Don't grow, don't shrink, stay at 200px */
}
.item-fluid {
flex: 1 1 0; /* Grow to fill space, shrink if needed, start from 0 */
}
.sidebar {
flex: 0 0 300px; /* Fixed 300px sidebar */
}
.main-content {
flex: 1; /* Shorthand for: flex: 1 1 0 — takes remaining space */
}
/* Common pattern: two items sharing space proportionally */
.one-third {
flex: 1; /* Gets 1 part */
}
.two-thirds {
flex: 2; /* Gets 2 parts */
}
flex-wrap and gap
.card-row {
display: flex;
flex-wrap: wrap; /* Items wrap to next line when they run out of space */
gap: 20px; /* Space between items — works in both directions */
}
.card {
flex: 1 1 300px; /* Grow, shrink, but minimum 300px before wrapping */
}
order — Reordering Items Visually
/* Default order is 0 for all items */
.item-first {
order: -1; /* Moves to the beginning */
}
.item-last {
order: 99; /* Moves to the end */
}
/* Useful for responsive: sidebar first on mobile, last on desktop */
@media (max-width: 768px) {
.sidebar {
order: -1; /* Sidebar appears above main content on mobile */
}
}
Real Layout: Navigation Bar
<nav class="navbar">
<a href="/" class="logo">DreamWebCrafts</a>
<ul class="nav-links">
<li><a href="/services">Services</a></li>
<li><a href="/portfolio">Portfolio</a></li>
<li><a href="/blog">Blog</a></li>
</ul>
<a href="/contact" class="cta-button">Get a Quote</a>
</nav>
.navbar {
display: flex;
align-items: center;
justify-content: space-between;
padding: 1rem 2rem;
background: #1a1a2e;
}
.logo {
flex: 0 0 auto;
font-size: 1.5rem;
font-weight: bold;
color: #e94560;
text-decoration: none;
}
.nav-links {
display: flex;
list-style: none;
gap: 2rem;
margin: 0;
padding: 0;
}
.nav-links a {
color: #fff;
text-decoration: none;
}
.cta-button {
flex: 0 0 auto;
padding: 0.5rem 1.5rem;
background: #e94560;
color: #fff;
border-radius: 4px;
text-decoration: none;
}
/* Mobile: stack everything vertically */
@media (max-width: 768px) {
.navbar {
flex-direction: column;
gap: 1rem;
}
}
Real Layout: Perfect Centering
/* The classic — center anything horizontally and vertically */
.centered-container {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
/* Center text content with a max-width */
.hero-section {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
min-height: 80vh;
text-align: center;
padding: 2rem;
}
.hero-section h1 {
max-width: 800px;
}
Real Layout: Holy Grail Footer
/* Footer that always sticks to the bottom */
body {
display: flex;
flex-direction: column;
min-height: 100vh;
margin: 0;
}
header { flex: 0 0 auto; }
main { flex: 1; /* Takes all remaining space, pushes footer down */ }
footer { flex: 0 0 auto; }
CSS Grid Deep Dive
CSS Grid is a two-dimensional layout system. You define rows and columns simultaneously, then place items into that grid — explicitly by coordinates or implicitly by letting the browser auto-place them.
Defining Columns and Rows
.grid {
display: grid;
/* Three columns: 200px, flexible middle, 200px */
grid-template-columns: 200px 1fr 200px;
/* Two rows: auto height first, 300px second */
grid-template-rows: auto 300px;
gap: 20px;
}
The fr Unit
The fr unit represents a fraction of the available space in the grid container. It is the grid equivalent of flex-grow.
.grid {
display: grid;
/* First column gets 1 part, second gets 2 parts, third gets 1 part */
grid-template-columns: 1fr 2fr 1fr;
/* Total = 4 parts. Columns are 25%, 50%, 25% of available space */
}
repeat() — Avoiding Repetition
.grid {
display: grid;
/* Instead of: grid-template-columns: 1fr 1fr 1fr 1fr; */
grid-template-columns: repeat(4, 1fr);
/* Mixed patterns */
grid-template-columns: repeat(3, 100px 1fr); /* 100px 1fr 100px 1fr 100px 1fr */
}
minmax() — Flexible Constraints
.grid {
display: grid;
/* Columns are at least 200px, at most 1fr */
grid-template-columns: repeat(3, minmax(200px, 1fr));
/* Rows are at least 100px, grow to fit content */
grid-template-rows: repeat(3, minmax(100px, auto));
}
auto-fill vs auto-fit — Responsive Grid Without Media Queries
This is one of the most powerful CSS Grid features. It creates responsive column layouts with zero media queries.
/* auto-fill: Creates as many columns as fit, even if empty */
.grid-auto-fill {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 20px;
}
/* auto-fit: Same as auto-fill, but collapses empty tracks */
.grid-auto-fit {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
}
/* Practical difference:
With 2 items in a wide container:
- auto-fill: 2 items + empty columns maintaining 250px min
- auto-fit: 2 items stretch to fill ALL available space
*/
grid-area and Named Areas
Named grid areas let you define layouts in a visual, almost ASCII-art style. This is especially powerful for page-level layouts.
.page-layout {
display: grid;
grid-template-columns: 250px 1fr 300px;
grid-template-rows: 80px 1fr 60px;
grid-template-areas:
"header header header"
"sidebar content aside"
"footer footer footer";
min-height: 100vh;
gap: 0;
}
.header { grid-area: header; background: #1a1a2e; }
.sidebar { grid-area: sidebar; background: #16213e; }
.content { grid-area: content; padding: 2rem; }
.aside { grid-area: aside; background: #0f3460; }
.footer { grid-area: footer; background: #1a1a2e; }
/* Responsive: stack on mobile */
@media (max-width: 768px) {
.page-layout {
grid-template-columns: 1fr;
grid-template-rows: auto;
grid-template-areas:
"header"
"content"
"sidebar"
"aside"
"footer";
}
}
Explicit vs Implicit Grid
.grid {
display: grid;
/* Explicit: you define these tracks */
grid-template-columns: repeat(3, 1fr);
grid-template-rows: 200px 200px;
/* Implicit: browser creates these when items overflow the explicit grid */
grid-auto-rows: 150px; /* New rows default to 150px */
grid-auto-flow: row; /* default — fill row by row */
grid-auto-flow: dense; /* Fill gaps — items may reorder visually */
}
Spanning Cells
.featured-item {
grid-column: span 2; /* Takes up 2 columns */
grid-row: span 2; /* Takes up 2 rows */
}
/* Or use explicit line numbers */
.hero-banner {
grid-column: 1 / -1; /* Start at first line, end at last (-1) = full width */
grid-row: 1 / 3; /* Span first two rows */
}
Alignment in Grid
.grid {
display: grid;
grid-template-columns: repeat(3, 200px);
/* Align the entire grid within its container */
justify-content: center; /* Horizontal alignment of the grid itself */
align-content: center; /* Vertical alignment of the grid itself */
}
.grid-item {
/* Align content within its grid cell */
justify-self: center; /* Horizontal alignment within cell */
align-self: center; /* Vertical alignment within cell */
}
/* Shorthand to center everything in every cell */
.grid {
place-items: center; /* Sets both align-items and justify-items */
}
When to Use Which: The Decision Framework
Forget the oversimplified "Flexbox for 1D, Grid for 2D" advice. Here is a practical decision flowchart that covers real scenarios:
Use Flexbox When:
- You need items to flow in a single direction (a row of buttons, a vertical stack of cards)
- Content size should determine the layout (items grow and shrink based on their content)
- You need to distribute extra space among items proportionally
- You are building component-level layout (inside a card, inside a nav bar, inside a form group)
- You want items to wrap naturally when they run out of space
- Vertical centering is the primary goal
Use Grid When:
- You need precise control over both rows AND columns simultaneously
- The layout structure is defined by the container, not the content
- You want items to align to a strict grid structure
- You are building page-level layout (header, sidebar, content, footer)
- You need items to span multiple rows or columns
- You want a responsive multi-column layout without media queries (auto-fill/auto-fit)
- You want to use named grid areas for readable layout definitions
The Hybrid Approach (Most Common in Production)
In real-world projects, you almost always use both. Grid defines the page skeleton. Flexbox handles the internal component layout.
/* Grid for page layout */
.app-shell {
display: grid;
grid-template-columns: 250px 1fr;
grid-template-rows: 60px 1fr;
grid-template-areas:
"sidebar header"
"sidebar main";
min-height: 100vh;
}
/* Flexbox for the header's internal layout */
.header {
grid-area: header;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 2rem;
background: #fff;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
/* Flexbox for sidebar navigation */
.sidebar {
grid-area: sidebar;
display: flex;
flex-direction: column;
gap: 4px;
padding: 1rem;
background: #1a1a2e;
}
/* Grid for the main content area's card layout */
.main {
grid-area: main;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 24px;
padding: 2rem;
}
/* Flexbox for individual card internals */
.card {
display: flex;
flex-direction: column;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.card-body {
flex: 1; /* Push footer to bottom of card */
padding: 1.5rem;
}
.card-footer {
padding: 1rem 1.5rem;
border-top: 1px solid #eee;
display: flex;
justify-content: space-between;
align-items: center;
}
Real-World Layouts Rebuilt
Dashboard Layout
.dashboard {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-rows: auto auto 1fr;
gap: 24px;
padding: 24px;
}
/* Stats cards span one column each */
.stat-card {
padding: 1.5rem;
border-radius: 8px;
background: #fff;
display: flex;
flex-direction: column;
gap: 0.5rem;
}
/* Chart takes 3 columns */
.chart-main {
grid-column: span 3;
min-height: 400px;
background: #fff;
border-radius: 8px;
padding: 1.5rem;
}
/* Activity feed takes 1 column */
.activity-feed {
grid-column: span 1;
background: #fff;
border-radius: 8px;
padding: 1.5rem;
}
/* Data table spans full width */
.data-table-wrapper {
grid-column: 1 / -1;
overflow-x: auto;
}
@media (max-width: 1024px) {
.dashboard {
grid-template-columns: repeat(2, 1fr);
}
.chart-main {
grid-column: 1 / -1;
}
.activity-feed {
grid-column: 1 / -1;
}
}
@media (max-width: 600px) {
.dashboard {
grid-template-columns: 1fr;
}
}
Magazine Layout
.magazine-grid {
display: grid;
grid-template-columns: repeat(6, 1fr);
grid-template-rows: 400px 200px 200px;
gap: 16px;
}
/* Hero article */
.article-hero {
grid-column: 1 / 5;
grid-row: 1 / 2;
position: relative;
overflow: hidden;
border-radius: 8px;
}
/* Featured sidebar articles */
.article-featured-1 {
grid-column: 5 / 7;
grid-row: 1 / 2;
}
/* Second row articles */
.article-secondary {
grid-column: span 2;
}
.article-hero img,
.article-featured-1 img {
width: 100%;
height: 100%;
object-fit: cover;
}
@media (max-width: 768px) {
.magazine-grid {
grid-template-columns: 1fr;
grid-template-rows: auto;
}
.article-hero,
.article-featured-1,
.article-secondary {
grid-column: 1;
}
}
Responsive Image Gallery
.gallery {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 16px;
padding: 16px;
}
.gallery-item {
position: relative;
overflow: hidden;
border-radius: 8px;
aspect-ratio: 1; /* Perfect squares */
}
.gallery-item img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.3s ease;
}
.gallery-item:hover img {
transform: scale(1.05);
}
/* Feature certain images at double size */
.gallery-item.featured {
grid-column: span 2;
grid-row: span 2;
}
/* Masonry-like effect using grid-auto-flow: dense */
.gallery-masonry {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
grid-auto-rows: 200px;
grid-auto-flow: dense;
gap: 12px;
}
.gallery-masonry .tall {
grid-row: span 2;
}
.gallery-masonry .wide {
grid-column: span 2;
}
Pricing Cards
<div class="pricing-grid">
<div class="pricing-card">
<h3>Starter</h3>
<div class="price">$29<span>/mo</span></div>
<ul class="features">
<li>5 Pages</li>
<li>Basic SEO</li>
<li>Contact Form</li>
</ul>
<button class="btn">Get Started</button>
</div>
<div class="pricing-card popular">
<span class="badge">Most Popular</span>
<h3>Professional</h3>
<div class="price">$79<span>/mo</span></div>
<ul class="features">
<li>15 Pages</li>
<li>Advanced SEO</li>
<li>E-commerce</li>
<li>Blog</li>
</ul>
<button class="btn btn-primary">Get Started</button>
</div>
<div class="pricing-card">
<h3>Enterprise</h3>
<div class="price">$199<span>/mo</span></div>
<ul class="features">
<li>Unlimited Pages</li>
<li>Custom Integrations</li>
<li>Priority Support</li>
<li>SLA Guarantee</li>
</ul>
<button class="btn">Contact Us</button>
</div>
</div>
/* Grid for the pricing section, Flexbox inside each card */
.pricing-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 32px;
max-width: 1000px;
margin: 0 auto;
padding: 2rem;
align-items: start;
}
.pricing-card {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
padding: 2.5rem 2rem;
border-radius: 12px;
background: #fff;
box-shadow: 0 4px 12px rgba(0,0,0,0.08);
position: relative;
}
.pricing-card.popular {
transform: scale(1.05);
box-shadow: 0 8px 24px rgba(233,69,96,0.2);
border: 2px solid #e94560;
}
.price {
font-size: 3rem;
font-weight: 700;
margin: 1rem 0;
}
.price span {
font-size: 1rem;
color: #888;
}
.features {
list-style: none;
padding: 0;
margin: 1.5rem 0;
width: 100%;
}
.features li {
padding: 0.75rem 0;
border-bottom: 1px solid #f0f0f0;
}
.btn {
margin-top: auto; /* Flexbox pushes button to bottom regardless of content height */
padding: 0.75rem 2rem;
border: 2px solid #1a1a2e;
border-radius: 6px;
background: transparent;
cursor: pointer;
font-weight: 600;
width: 100%;
}
.btn-primary {
background: #e94560;
color: #fff;
border-color: #e94560;
}
CSS Container Queries Integration
Container queries let components respond to their own container size rather than the viewport. This makes components truly reusable across different layout contexts.
/* Define a containment context */
.card-container {
container-type: inline-size;
container-name: card;
}
/* Card layout changes based on ITS CONTAINER width, not viewport */
.card-inner {
display: flex;
flex-direction: column;
}
@container card (min-width: 400px) {
.card-inner {
flex-direction: row;
gap: 1.5rem;
}
.card-inner img {
width: 40%;
object-fit: cover;
}
}
@container card (min-width: 700px) {
.card-inner img {
width: 50%;
}
.card-inner .card-body {
font-size: 1.1rem;
}
}
Container queries pair beautifully with Grid. Your Grid controls where components are placed and how much space they get. Container queries let the components adapt to whatever space they are given.
Subgrid Support
Subgrid allows a grid item's children to participate in the parent grid's track sizing. This solves the classic problem of aligning content across sibling grid items.
.parent-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 24px;
}
.card {
display: grid;
grid-template-rows: subgrid; /* Card's rows align with parent grid's rows */
grid-row: span 3; /* Card spans 3 row tracks */
}
/* Without subgrid: card headers, bodies, and footers may be different heights
With subgrid: all card headers align, all bodies align, all footers align */
/* Real example: aligned card grid */
.product-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
grid-auto-rows: auto auto 1fr auto; /* image, title, description, price */
gap: 24px;
}
.product-card {
display: grid;
grid-template-rows: subgrid;
grid-row: span 4;
border-radius: 12px;
overflow: hidden;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.product-card img { grid-row: 1; }
.product-card h3 { grid-row: 2; padding: 0 1rem; }
.product-card p { grid-row: 3; padding: 0 1rem; }
.product-card .price { grid-row: 4; padding: 1rem; font-weight: bold; }
Common Layout Bugs and Fixes
Problem: Content Overflows Its Container
Cause: A flex or grid item's content is wider than the available space, often caused by long words, URLs, or pre blocks.
/* FIX: Prevent overflow */
.item {
min-width: 0; /* Override Flexbox/Grid default min-width: auto */
overflow-wrap: break-word;
word-break: break-word;
}
/* For pre/code blocks */
pre {
overflow-x: auto; /* Scroll instead of overflowing */
max-width: 100%;
}
/* For images */
img {
max-width: 100%;
height: auto;
}
Problem: Grid Items Not Equal Height
Cause: Using align-items: start instead of the default stretch, or content height varies between items.
/* FIX: Let Grid handle equal heights naturally */
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
align-items: stretch; /* Default — all items same height per row */
}
/* If you need cards to have equal height with a footer pinned to bottom */
.card {
display: flex;
flex-direction: column;
}
.card-body { flex: 1; } /* Takes available space, pushes footer down */
.card-footer { flex: 0 0 auto; }
Problem: Flex Items Not Wrapping Properly
Cause: Missing flex-wrap: wrap, or flex-basis is set to 0 (items shrink to nothing before wrapping).
/* BAD: Items shrink but never wrap */
.container {
display: flex;
}
.item {
flex: 1; /* flex: 1 1 0 — basis is 0, items shrink infinitely */
}
/* FIX: Set a minimum basis so wrapping triggers */
.container {
display: flex;
flex-wrap: wrap;
gap: 16px;
}
.item {
flex: 1 1 300px; /* Minimum 300px before wrapping to next line */
}
Problem: Grid Blowout on Small Screens
Cause: Fixed column sizes that exceed viewport width on mobile.
/* BAD */
.grid {
display: grid;
grid-template-columns: 300px 1fr 300px; /* 600px+ minimum — breaks on mobile */
}
/* FIX: Use minmax or media queries */
.grid {
display: grid;
grid-template-columns: minmax(0, 300px) 1fr minmax(0, 300px);
}
/* Or collapse to single column on mobile */
@media (max-width: 768px) {
.grid {
grid-template-columns: 1fr;
}
}
Performance Considerations
Both Flexbox and Grid are highly optimized in modern browsers, but some patterns cause more layout recalculations than others.
- Avoid deeply nested flex containers. Each level of nesting triggers its own layout calculation. If you have flex inside flex inside flex, consider whether Grid could flatten the structure.
- Use
contain: layouton components. This tells the browser that changes inside a component do not affect layout outside it, enabling paint optimizations. - Prefer Grid for known structures. Grid's layout is calculated once from the container down. Flexbox sometimes requires multiple passes when items wrap.
- Avoid changing
grid-template-*properties in animations. These trigger full layout recalculations. Animatetransformandopacityinstead. - Use
will-change: transformsparingly. Only apply it to elements you are actually animating, and remove it after the animation completes.
/* Performance-optimized component */
.optimized-card {
contain: layout style paint;
content-visibility: auto; /* Browser skips rendering off-screen cards */
contain-intrinsic-size: 0 400px; /* Placeholder size for skipped cards */
}
Accessibility with CSS Layout
CSS layout can accidentally break accessibility if visual order does not match DOM order. Screen readers follow the DOM, not the visual layout.
/* WARNING: Visual order != DOM order */
.grid {
display: grid;
}
.sidebar { order: 2; } /* Visually second, but DOM is first */
.content { order: 1; } /* Visually first, but DOM is second */
/* This confuses keyboard navigation — Tab order follows DOM */
/* BETTER: Structure your HTML in logical reading order, use Grid placement */
.grid {
display: grid;
grid-template-columns: 1fr 300px;
}
/* Content is first in DOM AND visually */
/* Sidebar is second in DOM and placed in the second column */
- Keep DOM order logical. Use Grid's placement features instead of
orderto reposition items visually. - Test keyboard navigation after applying layout changes.
- Use
aria-labelfor navigation landmarks so screen readers can identify regions regardless of visual layout. - Never use
display: noneto hide content you want screen readers to access. Useposition: absolute; clip: rect(0,0,0,0)instead.
Troubleshooting Quick Reference
| Problem | Cause | Solution |
|---|---|---|
| Items overflow container | Default min-width: auto prevents shrinking below content size | Add min-width: 0 to flex/grid items |
| Flex items all same width | Using flex: 1 makes all items share space equally | Use flex-basis or width for specific sizing |
| Grid items not aligning | Implicit rows created with auto sizing | Set grid-auto-rows to control implicit row heights |
| Gap not working in Flexbox | Older browser (pre-2021 Safari) | Use margin as fallback or update target browsers |
| auto-fit columns not stretching | Container has no explicit width | Ensure parent has defined width or is in normal flow |
| Cards have different heights | align-items set to something other than stretch | Use align-items: stretch (default) or subgrid |
| Content pushes sidebar off-screen | Content has no overflow handling | Add overflow: hidden or min-width: 0 to content area |
Cheat Sheet: Flexbox vs Grid at a Glance
| Feature | Flexbox | Grid |
|---|---|---|
| Dimension | One (row OR column) | Two (rows AND columns) |
| Content vs Layout driven | Content drives size | Layout drives size |
| Best for | Component internals | Page structure |
| Alignment | justify-content, align-items | justify/align-content, justify/align-items, justify/align-self |
| Responsive without media queries | flex-wrap + flex-basis | auto-fit/auto-fill + minmax() |
| Named areas | No | Yes (grid-template-areas) |
| Spanning | No | Yes (grid-column/row: span N) |
| Gap support | Yes (modern browsers) | Yes |
| Subgrid | No | Yes (Firefox, Chrome 117+, Safari 16+) |
| Item ordering | order property | Explicit placement + order |
/* Quick Reference: Most Common Patterns */
/* Center anything */
.center { display: flex; justify-content: center; align-items: center; }
/* or */
.center { display: grid; place-items: center; }
/* Responsive card grid (no media queries) */
.cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 24px; }
/* Sticky footer */
body { display: flex; flex-direction: column; min-height: 100vh; }
main { flex: 1; }
/* Sidebar layout */
.layout { display: grid; grid-template-columns: 250px 1fr; }
/* Equal height cards with footer pinned to bottom */
.card { display: flex; flex-direction: column; }
.card-body { flex: 1; }
/* Full-bleed inside constrained container */
.full-bleed { width: 100vw; margin-left: calc(50% - 50vw); }
Flexbox and Grid are not competitors — they are collaborators. Grid structures your pages. Flexbox handles your components. Together, they replace every layout hack we spent years learning. The key is recognizing which tool fits the problem in front of you, and this guide gives you the framework to make that call confidently every time. At DreamWebCrafts, we build responsive, accessible layouts that look sharp on every device — whether it is a marketing site, a SaaS dashboard, or a complex web application. If you need layouts that just work, our front-end team is here to make it happen.