1. The Viewport Meta Tag
Every HTML page you've created already has this line in the <head>:
<meta name="viewport" content="width=device-width, initial-scale=1.0">
Without this tag, mobile browsers render pages at ~980px wide and then zoom out to fit — making everything tiny and unreadable. This tag tells the browser: "Match the viewport width to the device width. Don't zoom out." (MDN: Viewport meta tag)
2. Mobile-First: The Right Way to Think
There are two approaches to responsive design:
| Approach | Base Styles For | Media Queries Add |
|---|---|---|
| Desktop-First ❌ | Large screens | max-width to shrink down |
| Mobile-First ✅ | Small screens | min-width to expand up |
Why Mobile-First Wins
1. Simpler base CSS. A mobile layout is usually a single column — the simplest structure. You start simple and add complexity.2. Progressive enhancement. Small screens get fast-loading minimal CSS. Larger screens get extra features. If a media query fails, the site still works.
3. Industry standard. Every modern CSS framework (Tailwind, Bootstrap) is mobile-first. Every professional developer thinks this way.
(web.dev: Responsive web design basics)
/* BASE: Mobile styles (no media query needed) */
.cards {
display: grid;
grid-template-columns: 1fr; /* Single column on mobile */
gap: 16px;
}
/* TABLET: 2 columns at 600px+ */
@media (min-width: 600px) {
.cards {
grid-template-columns: 1fr 1fr;
}
}
/* DESKTOP: 3 columns at 1024px+ */
@media (min-width: 1024px) {
.cards {
grid-template-columns: 1fr 1fr 1fr;
}
}
Notice: the base styles have no media query. They're the default. Media queries only add overrides for larger screens using min-width.
3. Media Queries: The Syntax
A media query is a CSS @media rule that applies styles only when a condition is true:
@media (min-width: 768px) {
/* These styles ONLY apply when viewport is 768px or wider */
.sidebar {
display: block;
}
}
The rules inside the @media block are ignored when the condition is false. When the viewport meets the condition, those rules activate and override base styles (normal CSS cascade rules apply). (MDN: Using media queries)
Common Breakpoints
There's no "official" set, but these are the most widely used:
| Breakpoint | Target | Usage |
|---|---|---|
480px |
Large phones | Rarely needed if base styles are mobile-first |
600px |
Small tablets / landscape phones | Switch from 1-column to 2-column |
768px |
Tablets | Show sidebar, expand navigation |
1024px |
Small desktops / laptops | Full desktop layout |
1280px |
Large desktops | Extra-wide layouts, max-width containers |
4. See It In Action
Click the viewport buttons below to see how media queries change the layout at different screen sizes:
At 320px: single column. At 480px: 2 columns. At 768px: 3 columns. The base CSS is mobile-first — the @media rules only add columns as space permits.
5. Fluid Typography with clamp()
Hard-coding font sizes creates problems. 3rem looks great on desktop but overwhelms a phone screen. You could use media queries, but there's a better way — clamp():
h1 {
/* clamp(minimum, preferred, maximum) */
font-size: clamp(1.8rem, 4vw + 1rem, 3.5rem);
}
p {
font-size: clamp(0.95rem, 1.5vw + 0.5rem, 1.15rem);
}
How clamp() works:
- Minimum (1.8rem) — font never shrinks below this, even on tiny screens
- Preferred (4vw + 1rem) — scales with the viewport width.
vw= 1% of viewport width - Maximum (3.5rem) — font never grows past this, even on ultrawide monitors
The result: smooth, proportional scaling with no media queries and no jumps. The browser calculates the right size for every viewport width automatically. (MDN: clamp())
padding: clamp(1rem, 3vw, 3rem) gives you fluid spacing.
6. Responsive Images
By default, images render at their intrinsic pixel size. A 2000px-wide photo will overflow a 375px phone screen. The fix is one CSS rule:
img {
max-width: 100%;
height: auto;
display: block;
}
max-width: 100%— image never exceeds its container widthheight: auto— maintain aspect ratio (prevents squishing)display: block— removes the mysterious 4px gap below images (images are inline by default)
This single rule should be in every CSS reset you ever write. It makes all images fluid by default. (MDN: Images in CSS)
The srcset Attribute (Performance)
For production sites, you'll want to serve different image sizes to different devices — no point sending a 2MB desktop image to a phone on 4G:
<img
src="photo-800.jpg"
srcset="photo-400.jpg 400w,
photo-800.jpg 800w,
photo-1200.jpg 1200w"
sizes="(max-width: 600px) 100vw,
(max-width: 1024px) 50vw,
33vw"
alt="Project screenshot"
>
The browser selects the best image based on the device's viewport width and pixel density. You don't need to master srcset right now — just know it exists. You'll use it in production projects later. (MDN: Responsive images)
7. Common Responsive Patterns
Pattern 1: Hidden Sidebar on Mobile
/* Mobile: sidebar hidden */
.sidebar {
display: none;
}
/* Desktop: show sidebar */
@media (min-width: 768px) {
.page {
display: grid;
grid-template-columns: 250px 1fr;
}
.sidebar {
display: block;
}
}
Pattern 2: Stack Navigation on Mobile
/* Mobile: stack nav vertically */
.nav {
display: flex;
flex-direction: column;
gap: 8px;
}
/* Desktop: horizontal nav */
@media (min-width: 768px) {
.nav {
flex-direction: row;
justify-content: space-between;
align-items: center;
}
}
Pattern 3: Fluid Container with Max-Width
.container {
width: 100%;
max-width: 1200px;
margin: 0 auto;
padding: 0 clamp(1rem, 3vw, 3rem);
}
This is the universal container pattern. Full width on mobile, capped at 1200px on desktop, auto-centered, with fluid padding that scales between 1rem and 3rem. You'll use this on every project.
Pattern 4: Responsive Grid (No Media Queries)
/* You learned this in Lesson 7 — now you see why it matters */
.cards {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 24px;
}
This was introduced in Lesson 7, but now you understand why it's so powerful — it's a responsive pattern that doesn't need a single media query.
8. Responsive Units: The Full Picture
You've seen px, rem, %, and now vw. Here's when to use each:
| Unit | Relative To | Best For |
|---|---|---|
px |
Nothing (absolute) | Borders, shadows, thin lines — things that shouldn't scale |
rem |
Root font size (usually 16px) | Font sizes, spacing, most dimensions — the default choice |
em |
Parent element's font size | Component-internal spacing (padding relative to text size) |
% |
Parent element's size | Widths inside containers, flexible grid tracks |
vw / vh |
Viewport width / height | Full-screen sections, fluid typography inside clamp() |
fr |
Remaining space in grid | CSS Grid column/row sizing only |
rem for almost everything. Use px for borders and box-shadows. Use % for widths. Use vw only inside clamp(). Use fr only in Grid. When in doubt, use rem.
9. Testing Responsiveness
You don't need a phone to test mobile layouts. Every browser has built-in device simulation:
- Open DevTools: Press
F12orCtrl + Shift + I - Toggle device toolbar: Press
Ctrl + Shift + M(or click the phone/tablet icon) - Select a device: Choose "iPhone 14", "iPad", etc. from the dropdown
- Drag the handles: Resize the viewport freely to find where your layout breaks
10. Test Your Knowledge
Quiz: Responsive Design
min-width to layer on styles for larger viewports.min-width: "at a minimum of X width, apply these styles." Desktop-first uses max-width.width=device-width do?clamp(1rem, 3vw + 0.5rem, 2rem) do?clamp(min, preferred, max) means: use the preferred value, but never go below min or above max. It creates smooth, bounded scaling.max-width: 100% essential on images?max-width: 100% constrains images to their container.max-width: 100% caps them at the container width, preventing horizontal overflow.@media (min-width: ...) adds overrides for larger screens.repeat(auto-fill, minmax(...)) creates as many columns as fit, auto-reflowing as the viewport resizes — no media queries needed.repeat(auto-fill, minmax(250px, 1fr)) creates columns that are at least 250px, fitting as many as possible — fully responsive without media queries.11. Retrieval Practice: Fill In The Blanks
Write from memory. If you can't recall it, that's the point — effortful retrieval is how knowledge sticks.
12. Build Challenge: Responsive Portfolio
This is the capstone of Phase 2 (CSS). Take everything from Lessons 4–8 and build a fully responsive portfolio site from scratch. No templates. No copying. Your design, your code.
- Create
practices/lesson8-portfolio.htmlandpractices/lesson8-style.css - Start mobile-first — write all base styles for a 320px screen first:
- Single-column layout
- Stacked navigation (logo above links)
- Full-width cards
- Add a tablet breakpoint at
600px:- 2-column card grid
- Horizontal navigation
- Add a desktop breakpoint at
1024px:- 3-column card grid
- Max-width container (1200px) with auto margins
- Optional: sidebar layout
- Apply these responsive techniques:
- Fluid typography:
clamp()on h1, h2, and body text - Responsive images:
max-width: 100%; height: auto - Fluid container padding:
padding: 0 clamp(1rem, 3vw, 3rem) - CSS Grid or Flexbox — your choice per component
- Fluid typography:
- Test in DevTools: resize from 320px to 1400px. No horizontal scrollbars should appear at any width.
Primary Sources: web.dev: Responsive web design basics is Google's definitive guide. Also: MDN: Responsive design and Kevin Powell's responsive design playlist.
Finished the build? Type /teach and show me your portfolio. I'll review your responsive breakpoints, check for horizontal overflow, and verify mobile-first structure. After this, we move on to Phase 3: JavaScript.