Responsive & MotionIntermediate8 min08 / 9

Responsive Design

Learn how to build pages that look great on every screen size, from tiny phones to wide desktops, using mobile-first thinking, media queries, and fluid units.

Think about the last time you opened a website on your phone and it felt perfectly at home — text readable without zooming, buttons easy to tap, images that did not overflow the screen. That experience did not happen by accident. Someone wrote CSS that adapts to the screen the visitor happens to be using. That craft is called responsive design, and by the end of this lesson you will know exactly how to do it.

The four pillars are: the viewport meta tag, mobile-first thinking, media queries, and fluid units. We will cover each one in order.

#Step 1 — The Viewport Meta Tag

Always include this tag. Without it, mobile browsers pretend your page is ~980 px wide and shrink everything down, making your media queries fire at the wrong sizes.
<head>
  <meta charset="UTF-8">
  <!-- Required for responsive design -->
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>My Page</title>
  <link rel="stylesheet" href="style.css">
</head>

#Step 2 — Mobile-First Thinking

Think of it like

Pack a carry-on, then upgrade

If you start with a carry-on and pack only what you really need, you can always move to a larger bag and add more. If you start with a giant trunk and try to cram it into a carry-on later, nothing fits. Mobile-first CSS works the same way: write base styles for small screens, then layer on enhancements for wider ones.

In practice, mobile-first means your default CSS (outside any media query) targets small screens. You then use @media (min-width: ...) queries to progressively enhance the layout for wider viewports. This produces leaner, easier-to-maintain code than the older "desktop-first" approach that used max-width queries to strip things back.

#Step 3 — Media Queries and Breakpoints

A classic mobile-first responsive grid. The base style handles phones; media queries add columns as space grows.
/* Default (mobile) styles — no query needed */
.card-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.5rem;
  padding: 1rem;
}

/* Tablet: 600 px and wider */
@media (min-width: 600px) {
  .card-grid { grid-template-columns: repeat(2, 1fr); }
}

/* Desktop: 1024 px and wider */
@media (min-width: 1024px) {
  .card-grid { grid-template-columns: repeat(3, 1fr); }
}
Common mistake

min-width, not max-width

In mobile-first CSS you almost always use min-width ("apply when the viewport is at least this wide"). Using max-width everywhere reverses the logic and leads to a tangle of overrides. If you find yourself writing max-width queries constantly, you have likely started from desktop — flip your thinking.

Choose breakpoints where your content starts to look awkward, not based on specific device names. Common starting points: 480px, 600px, 768px, 1024px, 1280px.

#Step 4 — Fluid Units

Fixed pixels break when the screen is narrower. These fluid units scale naturally — clamp() is especially powerful for fluid typography.
/* % — relative to the parent container */
.sidebar { width: 30%; }

/* vw / vh — relative to the viewport */
.hero { height: 60vh; }

/* rem — relative to the root font size, great for spacing */
.section { padding: 2rem; }

/* clamp(min, preferred, max) — fluid between two limits */
h1 { font-size: clamp(1.5rem, 4vw, 3rem); }
Step 5 — Flexible Images. This three-line rule is the single most impactful responsive fix for media. Images scale down but never stretch beyond their natural size.
/* Add to your base / reset styles */
img,
video,
iframe {
  max-width: 100%;
  height: auto;
  display: block;
}
Quick check

Which attribute of the viewport meta tag tells a mobile browser to use the device's actual screen width?

Tip

Test at every width during development

In Chrome or Edge DevTools, press Ctrl + Shift + M (Mac: Cmd + Shift + M) to open device-emulation mode. Drag the viewport edge to any width and watch your layout respond. Make this part of your everyday workflow — do not wait until you are done to check mobile.

Key takeaways

  • Always include `<meta name="viewport" content="width=device-width, initial-scale=1.0">` — without it, responsive CSS will not work on real devices.
  • Write mobile-first: default styles target small screens, then `@media (min-width: ...)` layers on wider-screen enhancements.
  • Choose breakpoints where your content looks awkward, not based on specific device screen sizes.
  • Use fluid units (`%`, `vw`, `rem`, `clamp()`) so sizes scale naturally instead of overflowing or shrinking strangely.
  • One rule — `max-width: 100%; height: auto;` — makes all images and videos flexible with no overflow.
Practice challenges
Test yourself · earn XP
0/4
Predict the output#1

This is the mobile-first grid from the lesson. What layout appears when the browser is exactly 700px wide?

predict-output
.card-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.5rem;
}

@media (min-width: 600px) {
  .card-grid { grid-template-columns: repeat(2, 1fr); }
}

@media (min-width: 1024px) {
  .card-grid { grid-template-columns: repeat(3, 1fr); }
}
Fix the bug#2

This code has a bug — the viewport meta tag is not making the page use the device's real width. What's wrong?

fix-bug
<head>
  <meta charset="UTF-8">
  <meta name="viewport"
        content="width=980px, initial-scale=1.0">
  <title>My Page</title>
</head>
Fill in the blank#3

Complete this mobile-first media query so the enhancement applies on tablets that are 600px OR wider (not narrower).

@media (: 600px) {
  .card-grid { grid-template-columns: repeat(2, 1fr); }
}
Fill in the blank#4

Fill in the value that makes headings scale fluidly: never smaller than 1.5rem, never larger than 3rem, preferring 4vw in between.

h1 {
  font-size: (1.5rem, 4vw, 3rem);
}
Your turn
Practice exercise

Build a responsive navigation bar. On mobile (the default) the links should stack vertically. At 640 px and wider they should sit side by side in a horizontal row. Use mobile-first CSS with a single @media (min-width: 640px) query.

Try it live — edit the code and hit Run to see it rendered:

solution.css · editable