12: Responsive or It Didn't Happen

Your site on your phone should not look broken. One viewport tag, fluid units, and a single media query make it adapt to any width.

The viewport meta tag

Without this tag, phones render the page at about 980px wide and shrink it to fit. Text becomes tiny.

<meta name="viewport" content="width=device-width, initial-scale=1.0">

This line is in every module's <head>. With it, width equals the device width. Without it, mobile looks zoomed out.

Gotcha: If mobile looks tiny or zoomed out, you forgot the viewport meta. Check the head.

Units: %, em/rem, vh/vw

UnitRelative to…Use
%parentFluid widths
emown / parent font-sizeSpacing that scales with text
remroot (html) font-sizeConsistent sizing
vh / vwviewport height/widthHero sections, full-screen
width: 50%
half of parent
width: 50vw
half of viewport
font-size: 1.2rem
bigger than root
height: 40vh
40% of viewport height
html { font-size: 16px; } /* 1rem = 16px */
h1 { font-size: 2rem; }   /* 32px */
.card { padding: 1rem; width: 90%; max-width: 600px; }
.hero { height: 60vh; }   /* 60% of viewport height */

Media queries: mobile first

Write base styles for mobile, then add width with min-width. Use max-width only when you need to override desktop styles.

/* base: mobile (single column) */
.cards { display: grid; gap: 12px; }

/* tablet+ : 2 columns */
@media (min-width: 600px) {
  .cards { grid-template-columns: repeat(2, 1fr); }
}

/* desktop : 3 columns */
@media (min-width: 900px) {
  .cards { grid-template-columns: repeat(3, 1fr); }
}

Resize window to see cards reflow. flex-wrap and grid auto-fit do this without queries.

Card: flex:1 1 140px
Card
Card
Free responsiveness: flex-wrap: wrap and grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)) make grids responsive without media queries. Save queries for bigger layout shifts like stacking a header.

max-width containers and auto-fit

max-width: 480px; margin: 0 auto;
Caps width, centers, but shrinks on mobile
/* container pattern */
.container { max-width: 720px; margin: 0 auto; padding: 0 16px; }

/* grid that is responsive for free */
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 16px; }
/* auto-fit: as many 200px columns as fit; auto-fill is similar but keeps empty tracks */

Fluid type with clamp()

One line that scales font smoothly between mobile and desktop with no media queries.

I am clamp(18px, 4vw, 32px). Resize window to see me scale

Never smaller than 18px, never larger than 32px. Prefers 4vw in between.

h1 { font-size: clamp(1.5rem, 4vw, 2.5rem); }
p  { font-size: clamp(0.95rem, 2vw, 1.05rem); }

Live demo: one media query to stack header

Shrink window below 500px and the header stacks vertically. That is the media query.

header { display: flex; justify-content: space-between; }
@media (max-width: 500px) {
  header { flex-direction: column; }
}
Exercise: Make all previous pages responsive (15 min)
  1. Add <meta name="viewport"> if missing.
  2. Wrap content in .container { max-width: 720px; margin: 0 auto; padding: 0 16px; }
  3. Add one media query that stacks nav or grid on small screens.
  4. Try clamp() on one heading. Resize and watch it scale.
  5. Test with DevTools device toolbar (phone and tablet).
Prev11: Position & Stacking Next13: Typography That Doesn't Hurt Eyes