TYPENORMLabs8 minAugust 19, 2026

Responsive Web Design Techniques

The techniques that replaced the media-query pile: clamp() for fluid type, intrinsic grids, container queries, and srcset for images. What each one is for, and the rule for choosing between them.

A responsive stylesheet written in 2014 and one written today do the same job with almost no overlapping code. The old one is a stack of @media blocks, each re-declaring font sizes and column counts at a width someone picked off a device chart. The new one barely queries the viewport at all: the type scales itself, the grid counts its own columns, and the components ask about their container instead of the window.

For the conceptual ground, start with the complete guide, which covers what responsive design is and why breakpoints belong to content rather than devices. This piece assumes that and goes to the tooling.

Fluid type and space with clamp()

clamp() takes a floor, a preferred value, and a ceiling, and returns whichever is in the middle:

h1 {
  font-size: clamp(1.75rem, 1.25rem + 2.5vw, 3rem);
}

Three media-query steps collapse into one declaration, and the type never gets caught at an awkward in-between size, because there are no steps to be caught between.

One rule governs the whole function: write the middle value as a rem component plus a vw component, never vw alone. A pure-viewport preferred value like clamp(1rem, 4vw, 2rem) doesn't respond to browser zoom the way text must. The rem term is what keeps the value growing when someone zooms to 200%, which WCAG 1.4.4 requires you to support.

The close relative min() gives you the most useful width declaration in modern CSS:

.container {
  width: min(100% - 2rem, 65ch);
  margin-inline: auto;
}

A centered column capped at a comfortable measure, with a guaranteed gutter on narrow screens, in two lines and zero breakpoints.

Intrinsic layouts: let the grid count

The second technique hands the column math to Grid:

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 1.5rem;
}

The grid fits as many 240px-minimum columns as the space allows and distributes the remainder. No breakpoints, no counting, and it stays correct in a container you haven't built yet.

auto-fit and auto-fill are the part people get wrong, and the difference only shows when the items don't fill the row. auto-fill keeps the empty tracks it created, so three cards in a five-column space stay card-width with a gap to the right. auto-fit collapses those empty tracks, so the three cards stretch to fill the row. Neither is correct in general. Stretching looks right for a hero row of features and wrong for a search-results grid, where consistent card width across pages matters more than a flush edge. Pick per component.

Flexbox does the row-level version of the same trick with flex-wrap: wrap and a flex-basis. Reach for it when the items should size to their own content; Grid is right when they should size to a track.

Container queries: components that respond to where they are

A media query asks how wide the window is. That was always a proxy for the real question, which is how much room this component has. A card in a wide main column and the same card in a 300px sidebar want different layouts at the same viewport width, and no media query can tell them apart. Every workaround the old toolkit offered was some form of passing the page's layout down into the component: a .sidebar & selector, a size="compact" prop, a modifier class set by whoever placed it. All of them make the component know about its surroundings, which is the thing a component is supposed to not do.

Container queries close that gap. The parent declares itself a container; the child queries it:

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

@container (min-width: 30rem) {
  .card {
    grid-template-columns: 8rem 1fr;
  }
}

container-type: inline-size is the declaration that matters, and it is doing more than opting in. It establishes containment on the inline axis, which means the container's width can no longer be determined by its contents. That's the trade: you get to query the box, and in exchange the box stops sizing itself to what's inside it. Most layout containers already get their width from the grid or flex parent above them, so this costs nothing. Apply it to something that was shrink-to-fit and the layout changes under you. Silently.

Nesting is where the naming comes in. A card inside a panel inside a main column sits in three container contexts, and a bare @container query resolves against the nearest ancestor container on the queried axis, which may not be the one you meant. Name them and be explicit:

.panel { container: panel / inline-size; }

@container panel (min-width: 40rem) {
  .card { /* responds to the panel, not the wrapper */ }
}

The units are the other half. cqi is 1% of the container's inline size, the container-scoped answer to vw. A heading sized in cqi scales against its column rather than the window, which is what you wanted from vw in a component all along; the same card can then run its type scale correctly in a 1200px main and a 280px rail without either one knowing about the other. Container queries reached Baseline availability across all major engines in 2023, so for most projects the compatibility argument is over. When you do name a threshold, put it in the smallest scope that can answer the question; for a component that is always the container, never the viewport.

Responsive images: srcset, sizes, and reserved space

On a media-heavy page the images are the responsive problem, and a 2400px hero shipped to a phone is the single most expensive mistake in the category. srcset with w descriptors lets the browser choose:

<img
  src="/hero-800.jpg"
  srcset="/hero-400.jpg 400w, /hero-800.jpg 800w, /hero-1600.jpg 1600w"
  sizes="(min-width: 60rem) 50vw, 100vw"
  alt="..."
  width="1600"
  height="900"
/>

srcset lists what exists and how wide each file is. sizes is a promise about layout that the browser has to trust before it has any layout, which is why you state it instead of letting the box be measured. The browser combines those with the device pixel ratio and picks. Get sizes wrong and the mechanism quietly does nothing useful: a default of 100vw on an image that renders at half-width downloads roughly twice the pixels needed.

Use <picture> when the crop changes, not just the resolution. A wide establishing shot on desktop and a tight portrait on mobile is art direction, and srcset can't express it.

Then reserve the space. width and height attributes, or an aspect-ratio in CSS, let the browser hold the box before the file arrives, which is what stops the page from lurching as images load and what keeps you out of trouble on Cumulative Layout Shift.

What media queries are still for

Media queries didn't go away; they got demoted from the starting tool to the exception. What's left is the set of questions the other techniques can't answer, because they're environment questions, not size questions:

  • prefers-reduced-motion — the one nobody should skip. Wrap transforms and parallax in it.
  • prefers-color-scheme — theming against the system setting.
  • pointer and hover@media (hover: hover) is how a hover-reveal stops being a trap on touch, where there is no hover state to reveal it.
  • orientation — genuinely useful for a media player or a canvas tool, rarely for a document.
  • print — still the only way to strip nav and set page breaks.

Note what these have in common: none of them is a width. Width questions now belong to clamp(), intrinsic grids, and container queries. When you do need a width breakpoint, choose it from your own content, not from a device chart.

Choosing between the responsive web design techniques

What is the thing actually responding to?

The thing responds to…Reach for
Available space, continuouslyclamp(), min(), fluid spacing
How many items fitIntrinsic Grid (auto-fit / auto-fill)
Its own container's widthContainer queries, cqi units
Network and screen densitysrcset / sizes, <picture>
User or device capabilityMedia queries (prefers-*, hover, print)

One rule keeps the stylesheet from drifting back to 2014: prefer the technique that requires no threshold. A layout that never names a width can't be wrong at one.

Testing

Resize the browser slowly and watch for the moment something gets uncomfortable. That's still the core method, and devtools' responsive mode is fine for it. What that mode can't tell you is how a layout behaves when the on-screen keyboard eats half the viewport, whether a tap target is reachable one-handed, or how the page feels on a mid-range Android over cellular. Those failures only show on hardware. Check zoom to 200% while you're there; it's the fastest way to catch a vw-only clamp() you meant to fix.

Responsive web design techniques FAQ

What are the main responsive web design techniques? Fluid sizing with clamp() and min(), intrinsic layouts with Grid and Flexbox, container queries for component-level response, and srcset/sizes for images. Media queries handle what's left: user preferences, pointer type, print.

Do container queries replace media queries? For component layout, largely yes. For environment questions — reduced motion, color scheme, print, whether the device has a real hover — media queries are the only tool that asks the right question.

Is a fluid layout the same as a responsive one? Fluid describes the sizing: things scale continuously instead of in steps. Responsive is the broader goal, and a good implementation is mostly fluid with a few deliberate breaks where fluid alone stops being enough.

What's the most common responsive mistake? Shipping desktop-sized images to phones. It's invisible on a fast office connection and the most expensive thing on the page everywhere else.

Take it further

The auto-fit call is the shape of every decision on this page. Nothing in the CSS tells you whether three cards should stretch or hold their width; that's a judgment about what the grid is for, and no technique settles it for you. The next call worth having is where to break at all, which is breakpoint strategy; both live in the responsive design hub. And if the open question is which of these your own build already gets wrong, that's what a Full UX Audit scores.

Free UX Snapshot for 50 Product Teams

Apply now and get a complimentary UX Snapshot — our rapid clarity audit delivered in 48 hours. Limited to the first 50 products.

Apply for Free UX Snapshot

Related

Navigation Design

Zara UX Teardown: The Homepage That Doesn't Scroll

A UX teardown of Zara's public store: a homepage one screen tall, navigation reduced to grey hairlines, and a catalog that won't quote a price until you type into the search box.

TYPENORMLabs · 7 min · August 16, 2026

Ecommerce
Web
Navigation Design

Interaction Design

Whimsical UX Teardown: Free Until You Share It

A UX teardown of Whimsical's product pages: a whiteboard that sells speed by removing the blank canvas, and a free plan that gives away unlimited private boards while capping shared ones at three.

TYPENORMLabs · 6 min · August 6, 2026

Productivity
Web
Interaction Design

Research Methods

Writing Closed Questions in Research: Getting Answers You Can Count

A closed question fixes the answer set before anyone reads it, which is what makes it countable and what makes it fragile. The forms, the five ways the wording breaks, and how to pretest before you send.

TYPENORMLabs · 9 min · August 15, 2026

Research Methods
UX Writing
Web