Skip to main content

Responsive Web Design: Core Concepts

Responsive Web Design (RWD) is not a single technique — it's a philosophy and a set of interconnected CSS strategies that make websites adapt to any screen size, resolution, and device capability.

1. The Viewport

The viewport is the visible area of the web page inside the browser window. On mobile, the browser renders pages as if they are 980px wide by default (desktop width), then scales down — causing the notorious "tiny zoomed-out page" problem.

The viewport meta tag corrects this:

<meta name="viewport" content="width=device-width, initial-scale=1.0">
AttributeEffect
width=device-widthSets page width to the physical screen width
initial-scale=1.0No initial zoom applied
maximum-scale=1.0Prevents zooming (⚠️ harms accessibility — avoid)

2. Mobile-First Design: The Why

Mobile-first means writing base styles for the smallest screen and using min-width media queries to progressively add complexity for larger screens.

/* ✅ Mobile-First: Start simple, add complexity */
.container { padding: 1rem; } /* Mobile base */
@media (min-width: 768px) { .container { padding: 1rem 2rem; } } /* Tablet+ */
@media (min-width: 1024px) { .container { max-width: 1200px; margin: auto; } } /* Desktop+ */

/* ❌ Desktop-First: Start complex, then override */
.container { max-width: 1200px; margin: auto; padding: 1rem 2rem; }
@media (max-width: 1023px) { .container { max-width: 100%; } }
@media (max-width: 767px) { .container { padding: 1rem; } }

Why mobile-first wins:

  • Browsers on mobile download FEWER bytes (base styles only — not the full desktop overrides).
  • Simpler mental model: add features, don't strip them.
  • Forces content prioritization — you decide what's most important.

3. Relative Units: The Foundation of Fluid Design

Percentage %

Relative to the parent element's corresponding property:

.sidebar { width: 30%; } /* 30% of parent's width */
.hero { height: 50%; } /* 50% of parent's height (parent must have explicit height) */

em vs rem

/* em — relative to the element's own font-size (or parent's if unset) */
.card { padding: 1.5em; } /* 1.5× the card's font-size */

/* rem — relative to the ROOT element's font-size (html tag, usually 16px) */
h1 { font-size: 3rem; } /* 48px if root is 16px — predictable everywhere */
UnitRelative ToBest For
%Parent elementWidths, fluid layouts
emOwn font-sizePadding/margin that scales with text
remRoot font-sizeTypography, consistent spacing
vwViewport widthFull-width sections, fluid type
vhViewport heightHero sections, full-screen layouts
dvhDynamic viewport heightMobile (excludes browser chrome bar)
chWidth of 0 characterOptimal prose line length
svh / lvhSmall/Large viewportFine-grained mobile control

The dvh vs vh Problem on Mobile

100vh on mobile Safari includes the browser chrome (URL bar), causing the "100vh is too tall" bug. Use dvh (Dynamic Viewport Height) instead:

.hero {
min-height: 100vh; /* Fallback for older browsers */
min-height: 100dvh; /* Correct on modern mobile browsers */
}

4. Fluid Typography with clamp()

clamp(min, preferred, max) creates type that fluidly scales between screen sizes — no media queries needed:

:root {
--text-base: clamp(1rem, 0.85rem + 0.5vw, 1.125rem); /* 16–18px fluid */
--text-lg: clamp(1.125rem, 1rem + 0.75vw, 1.375rem); /* 18–22px fluid */
--text-xl: clamp(1.5rem, 1.2rem + 1.5vw, 2rem); /* 24–32px fluid */
--text-hero: clamp(2.5rem, 5vw + 1rem, 5rem); /* 40–80px fluid */
}

5. Flexible Spacing with clamp()

section {
padding: clamp(2rem, 5vw, 5rem); /* 32px on mobile → 80px on desktop */
}
.card {
padding: clamp(1rem, 3vw, 2rem);
}

6. Content Width Guidelines

.container {
width: 100%;
max-width: 1200px; /* Cap on very wide screens */
margin: 0 auto; /* Center horizontally */
padding: 0 clamp(1rem, 4vw, 2rem); /* Fluid side padding */
}

/* Optimal reading width for prose */
.article-body {
max-width: 72ch; /* ~72 characters per line — ideal for readability */
}

7. The Full Breakpoint Strategy

/* Base: Mobile (<640px) */

/* sm: Small tablet (≥640px) */
@media (min-width: 640px) { }

/* md: Tablet (≥768px) */
@media (min-width: 768px) { }

/* lg: Desktop (≥1024px) */
@media (min-width: 1024px) { }

/* xl: Large desktop (≥1280px) */
@media (min-width: 1280px) { }

/* 2xl: Extra wide (≥1536px) */
@media (min-width: 1536px) { }

[!TIP] Don't add breakpoints at arbitrary sizes. Add a breakpoint when the design breaks — not at "standard" sizes. Your content dictates the breakpoints.