Look closely at a hundred websites and you'll see the same few layouts again and again: a header with a main area and footer, a grid of cards, a sidebar next to content, a row of features that stacks on phones. Once you know how to build these layout patterns responsively, you can assemble almost any page from them.
Modern CSS makes these patterns short. Grid is ideal for two-dimensional page structure and card grids, and flexbox for rows of items that wrap. Many patterns need no media queries at all, because auto-fit, minmax() and flex-wrap let the content decide when to stack. Where a bigger change is needed, a single media query can rearrange a whole page with grid-template-areas.
In this lesson you'll build six patterns you'll reuse for years: the auto-fit card grid, the sidebar layout, the switcher, the holy grail page with named areas, the sticky footer, and the full-bleed article.
Pattern 1: The auto-fit card grid
.grid { display: grid; gap: 16px; grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr)); }minmax(240px, 1fr)means each column is at least 240px and shares the leftover space.auto-fitcreates as many columns as fit in a row.- Wrapping the minimum in
min(240px, 100%)stops a single column overflowing on screens narrower than 240px. auto-fillis similar, but keeps empty column tracks when there are few items, so cards don't stretch as wide.
Pattern 2: Sidebar and switcher with flexbox
The sidebar pattern puts a fixed-width side panel next to flexible content and stacks them when space runs out:
.with-sidebar { display: flex; flex-wrap: wrap; gap: 16px; }
.sidebar { flex: 1 1 240px; }
.content { flex: 999 1 400px; }The huge flex-grow on .content makes it take almost all the extra space. When the container is too narrow for 240 + 400 pixels, the items wrap into one column, with no media query. The switcher is the same idea for equal items: flex: 1 1 200px on each, so they sit in a row when they fit and stack when they don't.
Pattern 3: Page layout with grid-template-areas
.page { display: grid; grid-template-areas: "header" "main" "aside" "footer"; }
@media (min-width: 900px) {
.page {
grid-template-columns: 1fr 280px;
grid-template-areas:
"header header"
"main aside"
"footer footer";
}
}Named areas read like a picture of the layout. Each element is placed with grid-area: header and so on. On phones the areas stack in one column, and one media query redraws the whole map for wider screens. This is often called the holy grail layout: header, footer, main content and one or two sidebars.
CSS Responsive Layouts Syntax
Layout patterns
.cards { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr)); }
.with-sidebar { display: flex; flex-wrap: wrap; gap: 1rem; }
.with-sidebar > :first-child { flex: 1 1 240px; }
.with-sidebar > :last-child { flex: 999 1 400px; }
body { min-height: 100dvh; display: grid; grid-template-rows: auto 1fr auto; }
.page { display: grid; grid-template-areas: "header" "main" "footer"; }CSS Responsive Layouts Summary
repeat(auto-fit, minmax(min(240px, 100%), 1fr))makes a card grid with no media queries.- Flexbox with
flex-wrapand a largeflex-growmakes sidebars that stack automatically. grid-template-areasdescribes a page layout and can be redrawn in one media query.grid-template-rows: auto 1fr autowithmin-height: 100dvhgives a sticky footer.- Change visual order carefully; keep the HTML in reading order.
CSS Responsive Layouts Examples
Each example runs in the page. Edit the code and press Run to see what changes.
A holy grail page with named areas
Drag the result wider than 700px to see the layout change.
<div class="page">
<header>Header</header>
<nav>Navigation</nav>
<main>Main content</main>
<aside>Related links</aside>
<footer>Footer</footer>
</div>.page {
display: grid;
gap: 8px;
grid-template-areas: "header" "nav" "main" "aside" "footer";
font: 600 15px sans-serif;
}
.page > * { padding: 16px; border-radius: 8px; background: #e0e7ff; }
header { grid-area: header; } nav { grid-area: nav; } main { grid-area: main; min-height: 120px; background: #dcfce7; }
aside { grid-area: aside; } footer { grid-area: footer; }
@media (min-width: 700px) {
.page {
grid-template-columns: 160px 1fr 180px;
grid-template-areas:
"header header header"
"nav main aside"
"footer footer footer";
}
}Line-by-line explanation
- Line 4On phones every area stacks in one column.
- Lines 8 to 9Each element is assigned to a named area.
- Lines 12 to 17On wider screens, the same names are arranged into three columns.
A sidebar that stacks itself
No media query: narrow the panel and the sidebar drops above the content.
<div class="with-sidebar">
<aside class="side">Filters</aside>
<section class="content">Search results</section>
</div>.with-sidebar {
display: flex;
flex-wrap: wrap;
gap: 12px;
font: 600 15px sans-serif;
}
.side {
flex: 1 1 180px;
background: #fef3c7;
padding: 16px;
border-radius: 8px;
}
.content {
flex: 999 1 320px;
min-height: 140px;
background: #e0f2fe;
padding: 16px;
border-radius: 8px;
}Line-by-line explanation
- Line 3Items wrap when they don't fit side by side.
- Line 9The sidebar wants 180px.
- Line 16Content wants at least 320px and takes nearly all the spare space.
Sticky footer and full-bleed article
<div class="shell">
<header>Header</header>
<article class="article">
<p>Text stays in a comfortable reading column on every screen.</p>
<img class="full" src="https://picsum.photos/seed/bleed/1200/400" alt="Rolling hills" width="1200" height="400">
<p>Then the text continues in the column after the wide image.</p>
</article>
<footer>Footer stays at the bottom</footer>
</div>.shell {
min-height: 420px;
display: grid;
grid-template-rows: auto 1fr auto;
font-family: sans-serif;
}
header, footer { padding: 12px; background: #1f2937; color: white; }
.article {
display: grid;
grid-template-columns: 1fr min(40ch, 100% - 32px) 1fr;
align-content: start;
}
.article > * { grid-column: 2; }
.article > .full { grid-column: 1 / -1; width: 100%; height: auto; }Line-by-line explanation
- Lines 2 to 4The middle row grows, pushing the footer to the bottom. On a real page use
min-height: 100dvh. - Line 11A centre column for text, with flexible space on each side.
- Line 15The image spans all three columns, edge to edge.
Common CSS Responsive Layouts Mistakes
Using order to fix bad HTML
/* HTML: footer, main, header */
footer { order: 3; } header { order: 1; }/* HTML: header, main, footer, in reading order */Screen readers and the Tab key follow the HTML order, not the visual order.
minmax that overflows phones
.grid { grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); } /* overflows a 300px space */.grid { grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr)); }A footer floating halfway up short pages
footer { position: absolute; bottom: 0; } /* overlaps content on long pages */body { min-height: 100dvh; display: grid; grid-template-rows: auto 1fr auto; }CSS Responsive Layouts in Real Projects
Patterns in production
Online shops use auto-fit grids for product listings and sidebar layouts for filters. Dashboards use grid-template-areas for header, navigation and widgets. Blogs use the full-bleed pattern for wide photos in articles. The "Every Layout" approach, popular with front-end developers, builds whole sites from small intrinsic patterns like the sidebar and switcher, with very few media queries.
CSS Responsive Layouts Exercises
Answer each one and check it instantly. If you get stuck, open the hint before the answer.
Fit as many 200px columns as possible in each row.
.grid {
display: grid;
grid-template-columns: repeat(, minmax(200px, 1fr));
}
auto-fit creates as many columns as fit.Which property places an element in a named grid area?
What gives a sticky footer on short pages?
Why does .content { flex: 999 1 400px; } work in a sidebar layout?
The layout should stack on phones and show main and aside side by side from 600px using named areas. Fix the area names and the media query.
<div class="pg"><main class="m">Main</main><aside class="a">Aside</aside></div>.pg { display: grid; grid-template-areas: "main" "aside"; }
.m { grid-area: content; }
.a { grid-area: aside; }
@media (max-width: 600px) {
.pg { grid-template-columns: 2fr 1fr; grid-template-areas: "main aside"; }
}- Main uses the main area
- Mobile first media query
- Side by side on wide screens
CSS Responsive Layouts Quiz
5 questions to check what you learned.
Which tool suits a two-dimensional page layout best?
- float
- CSS grid
- inline-block
- tables
What's the difference between auto-fit and auto-fill?
- There's none
- auto-fit only works in flexbox
- auto-fill keeps empty tracks, so a few items don't stretch as wide
- auto-fill needs a media query
Why wrap the minimum in min(240px, 100%)?
- So a single column never overflows a container narrower than 240px
- To make cards bigger
- It's required syntax
- To add a gap
What does the full-bleed pattern's middle column do?
- Hides overflow
- Keeps text in a readable column while wide elements span all columns
- Centres images only
- Adds a sidebar
Why should you avoid using order to rearrange content heavily?
- It's slow
- It's not supported
- It breaks grid
- Keyboard and screen reader users follow the HTML order, which then doesn't match what they see
CSS Responsive Layouts Challenge
A product listing page
- Make
.pagea grid withgrid-template-areas: "filters" "list"andgap: 16px - Assign
.filterstofiltersand.listtolist - From
min-width: 800px, usegrid-template-columns: 220px 1frand areas"filters list" - Make
.lista grid withgrid-template-columns: repeat(auto-fit, minmax(min(180px, 100%), 1fr))andgap: 12px
<div class="page">
<aside class="filters">Filters</aside>
<section class="list">
<div class="item">Lamp</div><div class="item">Chair</div><div class="item">Rug</div>
</section>
</div>.item { padding: 20px; background: #f1f5f9; }
- Page uses named areas
- Page gap is 16px
- List is an auto-fit grid
- Wide screen layout in a media query