Responsive design
Status: 🟩 COMPLETE Last updated: 2026-06-19 Plain-English tagline: Designing once and having it look right on phones, tablets, and desktops. Layout that adapts to the size of the screen it’s on.
In plain English
A modern website might be viewed on a phone (360 pixels wide), a tablet (768 pixels), a laptop (1280 pixels), a 4K monitor (3840 pixels), or anything in between. Responsive design is the practice of building one website that adapts smoothly across all of those.
Instead of building “the desktop version” and a separate “mobile version,” you build one site whose layout reflows based on the viewport’s size. Columns collapse to a single column on narrow screens. Navigation collapses into a hamburger menu. Text resizes. Images shrink or get cropped intelligently.
In 2026, over 60% of web traffic is mobile. Designing only for desktop and “checking later if it works on mobile” produces broken experiences. The modern default is mobile-first: start the design at the smallest screen, then enhance for larger ones. It’s more disciplined and almost always produces better results.
Why it matters
- Most users are on mobile. A site that doesn’t work on phones loses most of its audience.
- Google penalizes non-responsive sites. Mobile-friendliness has been a ranking factor since 2015 and got more important in 2018 with mobile-first indexing.
- One codebase, not two. Responsive design means you maintain one site, not separate desktop and mobile versions.
- Future devices. Foldables, ultrawide monitors, smartwatch browsers — designing fluidly means you cover devices that don’t exist yet.
The three core techniques
Modern responsive design uses three intertwined techniques:
1. Fluid layouts (relative units, not pixels)
Use percentages, rem, em, %, vw, vh, fr, and auto — not fixed pixel widths. Layouts expand and contract with the viewport.
.container {
width: 90%; /* responsive — scales with viewport */
max-width: 1200px; /* but capped on huge screens */
margin: 0 auto;
}2. Flexible images and media
Images should never overflow their container:
img, video {
max-width: 100%;
height: auto;
}For more advanced cases, the <picture> element and srcset attribute let you serve different image sizes (and even different image crops) at different viewports — saving bandwidth on mobile.
3. Media queries (the conditional layer)
CSS rules that only apply within a size range:
/* Default: mobile styles */
.card {
padding: 8px;
font-size: 14px;
}
/* Tablet and up */
@media (min-width: 768px) {
.card {
padding: 16px;
font-size: 16px;
}
}
/* Desktop and up */
@media (min-width: 1024px) {
.card {
padding: 24px;
font-size: 18px;
}
}Modern CSS also has container queries (@container) — styles based on the size of a parent element, not the viewport. Useful for components that should adapt based on where they’re placed.
The viewport meta tag (don’t skip this)
The single most important HTML line for responsive design:
<meta name="viewport" content="width=device-width, initial-scale=1">Without it, mobile browsers pretend they’re 980px wide and render your site at that width, then scale the whole thing down — making everything tiny. With it, the browser uses its actual size and your media queries kick in correctly.
Next.js and most frameworks include this by default. But if you ever scaffold from scratch, add it.
Mobile-first vs desktop-first
Two ways to write your media queries:
Mobile-first (recommended)
Base styles apply to the smallest screen. Media queries with min-width add complexity for larger screens.
.nav { display: block; } /* mobile default: stacked */
@media (min-width: 768px) {
.nav { display: flex; } /* tablet+: side by side */
}Desktop-first
Base styles assume desktop. Media queries with max-width peel back complexity for smaller screens.
.nav { display: flex; }
@media (max-width: 767px) {
.nav { display: block; }
}Mobile-first wins because:
- The base styles match the most common use case (mobile)
- You’re forced to think about the constraints first; enhancements come later
- Smaller CSS payload for mobile users (the default rules are already mobile-friendly)
- Easier to add new breakpoints later
Tailwind, shadcn/ui, and most modern frameworks default to mobile-first.
Tailwind’s breakpoint system
Tailwind wraps media queries in utility class prefixes:
| Prefix | Activates at | Typical device |
|---|---|---|
| (none) | 0px+ | Mobile |
sm: | 640px+ | Large phones / small tablets |
md: | 768px+ | Tablets |
lg: | 1024px+ | Laptops |
xl: | 1280px+ | Desktops |
2xl: | 1536px+ | Large desktops |
Mobile-first by default:
<div class="text-sm md:text-base lg:text-lg">
Smaller on phone, larger on desktop
</div>
<div class="flex flex-col md:flex-row">
Stacked on mobile, side by side on tablet+
</div>Read left to right as: “starting at mobile, do X. At tablet, do Y instead. At laptop, do Z.”
Common patterns
Stacked → side-by-side
<div class="flex flex-col md:flex-row gap-4">
<Sidebar />
<Main />
</div>Sidebar above main content on mobile; side by side on tablet+.
Grid that reflows
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
{cards.map(...)}
</div>One column on phones, two on small tablets, three on laptops, four on big desktops.
Hamburger menu
Visible only on mobile; full nav on desktop:
<nav>
<button class="md:hidden">☰</button>
<ul class="hidden md:flex gap-6">...</ul>
</nav>Hide on mobile / show on desktop
<aside class="hidden lg:block">
Supplementary content
</aside>Responsive typography
<h1 class="text-2xl md:text-4xl lg:text-5xl font-bold">
Title that scales
</h1>Or with CSS clamp() for truly fluid sizing:
h1 {
font-size: clamp(1.5rem, 4vw, 3rem);
/* min 1.5rem, scales with viewport, max 3rem */
}Touch vs mouse — beyond just size
Mobile isn’t just “smaller screen.” It’s:
- Touch input — tap targets need to be larger (minimum 44×44 px per Apple, ~48 dp per Material)
- No hover —
:hoverstyles don’t fire on touch; don’t hide critical info behind hover - Slower CPUs — animations and heavy JS hurt mobile more
- Bandwidth constraints — image sizes matter
- Battery — long-running JS drains batteries
Responsive design conceptually includes these — though the techniques are mostly CSS, the goal is “works well on a phone,” which means more than just “layout fits.”
A concrete example: a responsive card grid
<section className="container mx-auto px-4 py-8">
<h1 className="text-3xl md:text-4xl lg:text-5xl font-bold mb-6">
Latest posts
</h1>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 md:gap-6">
{posts.map(post => (
<article key={post.id} className="p-4 md:p-6 bg-white rounded-lg shadow">
<img
src={post.image}
alt={post.title}
className="w-full h-48 object-cover rounded mb-3"
/>
<h2 className="text-lg md:text-xl font-semibold mb-2">
{post.title}
</h2>
<p className="text-sm md:text-base text-slate-600">
{post.excerpt}
</p>
</article>
))}
</div>
</section>What this does:
- Phone: 1 column, smaller text, tighter padding
- Small tablet (
sm): 2 columns - Laptop (
lg): 3 columns, larger text, more padding - Images always fit their container; aspect ratio enforced
- Container width capped on huge screens (
container mx-auto)
One layout, four-plus screen sizes covered.
Testing responsively
You don’t need real devices for most testing — but you should test more than just resizing your browser window:
- Browser DevTools device mode — Chrome / Firefox / Safari all have device emulators. Toggle with Cmd/Ctrl+Shift+M. Test multiple presets.
- Real device every so often — emulators get touch and viewport mostly right but miss small things (autofocus behavior, font rendering, scroll inertia).
- Throttling — DevTools can simulate slow 4G or even 3G. Eye-opening.
- Tools: BrowserStack, LambdaTest, Sauce Labs — paid services that run real browsers on real devices.
- Vercel preview URLs — the preview deployment for every Git branch is a real URL your phone can hit.
Common gotchas
-
Forgetting the viewport meta tag. Site looks fine in DevTools but tiny on a real phone. The meta tag fixes this.
-
100vhon mobile. Mobile browsers’ address bars resize on scroll, so100vhoverflows. The new100dvh(dynamic viewport height) accounts for this — use it. -
Hover-only interactions. Dropdowns or info panels triggered by
:hoverdon’t work on touch. Always provide a tap/click path too. -
Tiny tap targets. Buttons less than 44×44 px are hard to tap accurately. Increase padding even if the icon is small.
-
Horizontal overflow. A single element wider than the viewport (a wide table, a long URL without word-break, an inline image without
max-width: 100%) creates horizontal scroll on mobile. Almost always wrong. Addoverflow-x: autoon the parent if scroll is intentional; otherwise fix the element. -
Fixed pixel heights for content.
height: 400pxon a card breaks when text wraps differently at different sizes. Usemin-heightor let content size itself. -
Skipping intermediate breakpoints. Designs that work at 360px and 1440px but break at 768px because no one tested in between. Tablet sizes are real.
-
Loading all-sized images on mobile. Serving a 4000-pixel-wide hero image to a phone wastes bandwidth. Use
srcsetand Next.js’s<Image>component for automatic responsive images. -
Font size too small on mobile. 12px reads fine on desktop and is illegible on phones. Mobile-first: start at 14px minimum for body text, 16px is safer.
-
Sticky elements that cover content. A sticky header that’s 80px on desktop and 80px on mobile takes up a huge portion of a short mobile viewport. Make sticky elements smaller on mobile.
-
Testing only in Chrome. Safari on iOS has quirks (different scroll behavior, different
vhhandling, sometimes different layout). Test on Safari at least occasionally. -
Assuming pixel-perfect designs. A design mockup is at one size. Build the principles, not the exact pixels.
-
Hidden content on mobile that’s actually critical. “We hid the search bar on mobile to save space” — turns out search is the most-used feature on mobile. Hiding things has a cost.
See also
- HTML 🟩 — viewport meta lives here
- CSS 🟩 — media queries, layout primitives
- Tailwind CSS 🟩 — responsive prefixes
- Mobile-first thinking 🟥 — the design philosophy
- Accessibility (a11y) 🟩 — overlaps heavily with responsive
- Dark mode 🟩 — same media query mechanism
- Next.js 🟩 🟦 —
<Image>for responsive images - How-to: Set up dark mode 🟩
- Glossary: CSS, DOM
Sources
- MDN — Responsive design
- web.dev — Learn Responsive Design
- Smashing Magazine — Responsive Web Design tag
- A List Apart — Responsive Web Design (Ethan Marcotte, 2010) — the original article that coined the term