Responsive web design has been the default for a decade. But the tools have changed. Container queries have replaced most media-query hacks. clamp() has replaced most JavaScript-based font-size logic. Subgrid is now stable. This article covers the modern responsive toolkit: what works in 2026, what is obsolete, and the patterns that will keep your layouts working for the next five years.

What "responsive" actually means

A responsive website adapts its layout to the screen size and capabilities of the device. That includes phones, tablets, laptops, desktops, and the increasingly common large monitors and TVs. It also includes users who zoom in or out, who have custom font sizes, who use a screen reader, who have a slow connection.

The original recipe (Ethan Marcotte, 2010) was three ingredients: fluid grids, flexible images, and media queries. Those ingredients still hold up. What has changed is the techniques we use to implement them.

The viewport meta tag

If you do nothing else, add this to the <head> of every page:

&lt;meta name="viewport" content="width=device-width, initial-scale=1"&gt;

Without it, mobile browsers render the page at desktop width and shrink it to fit, making everything tiny. With it, the layout viewport matches the device width and media queries behave intuitively.

The clamp() function: fluid type and spacing

clamp(min, preferred, max) lets you express a value that scales smoothly between a minimum and maximum, with a preferred middle value that responds to the viewport. The classic pattern is fluid typography:

h1 {
  font-size: clamp(1.5rem, 4vw, 4rem);
}

That makes h1 a minimum of 1.5rem (24px), grows with viewport width, and caps at 4rem (64px). No media queries, no JavaScript. The same pattern works for spacing:

section {
  padding: clamp(1rem, 3vw, 3rem);
}

Use clamp() liberally. It removes a huge class of breakpoint-tweaking headaches.

Container queries: the revolution

Media queries ask "how big is the viewport?" Container queries ask "how big is my parent?" That single change unlocks layouts that respond to context, not screen size. A card component can lay out horizontally when it has 600px of width and vertically when it has 300px — regardless of whether the user is on a phone or desktop.

.card-container {
  container-type: inline-size;
  container-name: card;
}

@container card (min-width: 400px) {
  .card {
    display: grid;
    grid-template-columns: 1fr 2fr;
    gap: 1.5rem;
  }
}

Now your card has a horizontal layout in a wide sidebar and a stacked layout in a narrow one — automatically. The same component, the same HTML, two contexts. That is the magic of container queries.

Subgrid: aligning nested content

Subgrid is the CSS Grid feature that lets a grid item's children inherit the parent's track sizing. The pattern we discussed in our Grid article applies especially well to responsive design: when each card in a row needs its title, image, and description to align across cards, subgrid makes it trivial.

.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 1.5rem;
}
.card {
  display: grid;
  grid-template-rows: subgrid;
  grid-row: span 3;   /* title, image, description */
}

Subgrid is supported in every modern browser as of 2026. Use it for any layout where rows should align across siblings.

The new responsive units: svh, lvh, dvh

Old vh (viewport height) units are unreliable on mobile because the URL bar appears and disappears, changing the viewport height. The new units fix that:

  • svh — small viewport height (when the URL bar is visible). The smallest value.
  • lvh — large viewport height (when the URL bar is hidden). The largest value.
  • dvh — dynamic viewport height (current). The one you usually want.

Use dvh for hero sections and full-screen layouts that should fill the visible space exactly.

.hero {
  height: 100dvh;
}

The container query units: cqw, cqh

Just as the viewport has vw and vh, a container query context has cqw (container query width) and cqh (container query height). Use them to make values inside a container respond to the container's size:

.card {
  container-type: inline-size;
}
.card h2 {
  font-size: clamp(1.2rem, 5cqw, 2rem);
}

The h2's font-size scales with the card's width, not the viewport. Beautiful.

A responsive layout example

Let us put everything together. A blog post layout that works on every device:

body {
  margin: 0;
  font-family: system-ui;
  background: #0a0d18;
  color: #e9ecf5;
}

main {
  max-width: 70ch;
  margin: 0 auto;
  padding: clamp(1rem, 3vw, 3rem);
}

h1 {
  font-size: clamp(1.8rem, 5vw, 3rem);
  line-height: 1.2;
}

img {
  max-width: 100%;
  height: auto;
}

pre {
  overflow-x: auto;
  padding: 1rem;
  background: #1a2236;
  border-radius: 8px;
}

That single stylesheet produces a readable layout on phones, tablets, and giant monitors. No media queries required for the basics. Add them when you need breakpoints for major layout shifts (single column to multi-column, navigation patterns), not for typography tweaks.

Common pitfalls

  • Setting a fixed width in pixels on the body. Use max-width instead. Always.
  • Using vh for hero sections on mobile. Use dvh to avoid the URL bar glitch.
  • Designing for the desktop and then "fixing" mobile. Design mobile-first. Start with the small screen and add complexity as the viewport grows.
  • Forgetting touch targets. Buttons and links need to be at least 44x44px for comfortable tapping.
  • Hiding content on mobile. If it is not important enough to be readable on a phone, question whether it is important at all.

When to reach for a framework

For most marketing pages and simple apps, hand-written CSS with the modern toolkit is more than enough. Once you have a complex design system with dozens of components, shared across many pages, a framework like Tailwind or a component library like shadcn/ui can save real time.

Tailwind is a utility-first framework that generates CSS from short class names. It is controversial (some people love it, some hate it) but undeniably productive once you internalise the class names. shadcn/ui is a collection of pre-built accessible components you copy into your project and own. For most teams building React or Vue apps in 2026, shadcn/ui has become the default starting point.

Images and performance

Responsive design is not just about layout — it is about serving the right assets to the right device. Three tools make this manageable:

  • srcset and sizes attributes on images — let the browser pick the smallest image that fits.
  • The <picture> element — for art direction (different crops at different sizes).
  • Modern formats like AVIF and WebP — smaller files than JPEG for the same quality.
&lt;img src="hero.jpg"
     srcset="hero-400.jpg 400w, hero-800.jpg 800w, hero-1600.jpg 1600w"
     sizes="(min-width: 800px) 800px, 100vw"
     alt="A wide hero image"&gt;

The browser picks the smallest image that fits the current viewport, saving bandwidth on phones and delivering crisp images on desktops. The MDN responsive images guide is the canonical reference.

Dark mode and user preferences

Modern responsive design includes respecting the user's system preferences. The prefers-color-scheme media query lets you adapt:

:root {
  --bg: #ffffff;
  --fg: #1a1a1a;
}
@media (prefers-color-scheme: dark) {
  :root {
    --bg: #0a0d18;
    --fg: #e9ecf5;
  }
}
body {
  background: var(--bg);
  color: var(--fg);
}

Combine with a theme toggle that saves the user's preference in localStorage. The full pattern is in our Custom Properties article.

Performance budgets

A responsive site that loads slowly is worse than a non-responsive site that loads fast. Set a performance budget:

  • First Contentful Paint under 1.5 seconds on a slow 3G connection.
  • Total page weight under 1 MB for the initial load.
  • JavaScript under 100 KB compressed.

Measure with Lighthouse, WebPageTest, or your browser's Performance tab. If you exceed the budget, optimise: smaller images, defer non-critical JavaScript, lazy-load below-the-fold content.

Further reading

Responsive design has changed substantially since 2020. These are the references that match how we ship in 2026.

FAQ

What about media queries? Are they obsolete?

No. Container queries handle component-level responsiveness. Media queries still rule for page-level layout shifts (e.g. "show the sidebar only on screens wider than 1024px"). Use both.

What is the difference between mobile-first and desktop-first?

Mobile-first means your base styles target phones, with media queries that add complexity for larger screens. Desktop-first is the opposite. Mobile-first usually produces cleaner CSS because the default is the simplest case. It also matches the way responsive design was originally conceived.

How do I test responsive layouts?

Browser dev tools have a device mode that simulates phones and tablets. Chrome and Firefox both let you throttle the network connection and CPU too. Combine with real-device testing before shipping anything important.

What is the smallest screen size I need to support?

320px is the safe minimum (older iPhones). Anything narrower and the content becomes cramped. For text-heavy sites, 360px is the practical floor.

How do I handle landscape orientation?

Modern phones in landscape have viewport widths similar to small tablets. Designing for narrow viewports in any orientation usually covers both cases. Use orientation: landscape media queries sparingly.

A note on browser support

All the techniques in this article — clamp(), container queries, subgrid, dvh — are supported in every major browser as of 2026. If you need to support older browsers (Edge Legacy, Safari 14), check caniuse.com for each feature. For most modern projects, you can use all of these without polyfills.

What is the difference between fluid and responsive?

Fluid layouts scale proportionally to the viewport. Responsive layouts change structure at breakpoints. The two are complementary — most modern sites use both. clamp() gives you fluid behaviour; container and media queries give you responsive behaviour.

Should I use a CSS reset?

Yes. The default browser styles are inconsistent across browsers. A small reset (Normalize.css or the modern reset built into Tailwind preflight) makes your CSS more predictable. Just do not use a 200-line reset; you do not need most of it.

How do I handle ultra-wide monitors?

Cap your main content width with max-width: 70ch (or similar) so lines of text do not span the entire screen. The user can pan, but the readable area is comfortable.

How do I test on real devices?

BrowserStack and Sauce Labs offer cloud-based real-device testing. For quick local checks, the dev tools' device emulation is usually enough. Always verify on at least one real iPhone and one real Android before shipping.

Homework

Rebuild the favourite-thing page you have been working on using the modern responsive toolkit:

  • Use clamp() for the main heading and section spacing.
  • Convert the bulleted list into a card grid using auto-fit and minmax().
  • Add a container query to the cards so each one switches from vertical to horizontal at 400px width.
  • Use dvh for the page header.
  • Test by resizing your browser window from 320px to 1920px.

When the layout feels good at every size, you have internalised the modern responsive toolkit. For the underlying CSS Grid, see our Grid article.