October 8, 2026
How to make a perfect responsive website, in 2026
Breakpoint-era advice is obsolete. Fluid type, container queries, and Core Web Vitals are what responsive design actually means now
The premise hasn’t changed, the tools have
The original version of this article was written when “responsive” meant a handful of fixed breakpoints and a media query for each one — design the desktop layout, then patch it for tablet and phone widths with overrides. That approach always had a tell: it optimized for a small set of device widths and left everything in between unconsidered. A viewport at 850px got whatever the nearest breakpoint happened to produce, not a layout designed for 850px.
The underlying goal — one interface that holds up across an unpredictable range of screens — hasn’t changed. What’s changed is that CSS now has primitives built for exactly this, and most of the old workarounds are gone.
Fluid type and spacing with clamp()
Instead of a font-size that jumps between fixed values at each breakpoint,
clamp() lets a value scale continuously between a minimum and a maximum:
h1 {
font-size: clamp(1.75rem, 1.2rem + 2.5vw, 3rem);
}
Below the point where 1.2rem + 2.5vw equals 1.75rem, the heading holds
at the minimum. Above the point where it equals 3rem, it holds at the
maximum. Between those two points, it scales smoothly with viewport width
— no jump at a breakpoint, no viewport width where the type looks
noticeably wrong because it’s stuck at whatever the last breakpoint set.
The same pattern works for spacing, margins, and container widths, and it
removes most of the “one more breakpoint for this in-between size” problem
that used to accumulate in a stylesheet over a project’s lifetime.
Container queries: the piece that was actually missing
Media queries respond to viewport width. That’s a real limitation for component-based design, where a card, a sidebar module, or a nav item needs to adapt to the width of its container, not the width of the browser window — the same card might sit in a wide main column on one page and a narrow sidebar on another, and a viewport-based media query can’t tell those apart.
.card-container {
container-type: inline-size;
}
@container (min-width: 480px) {
.card {
grid-template-columns: 12rem 1fr;
}
}
This is the single biggest addition to CSS’s responsive toolkit since the original version of this article, and it changes how components get built: a component can genuinely be responsive to where it’s placed, not just to the viewport, which is what “component-based design” was always supposed to mean and couldn’t quite deliver before.
Modern layout replaced most of the old hacks
display: none to hide content on mobile was already bad practice a
decade ago — the content still downloads, so you pay the weight without
showing the result, and it’s an accessibility problem for anyone using a
screen reader that doesn’t respect the visual breakpoint. That advice still
holds. What’s different is that CSS Grid and Flexbox now handle most of
what used to require float-based layout and JavaScript-driven reflows:
.layout {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
gap: 1.5rem;
}
That single rule replaces a whole category of breakpoint-specific column-count overrides — the grid reflows its own column count based on available space, without a media query telling it when to do so.
Core Web Vitals are the actual measurement, not “looks fine on my phone”
“Perfect” for a responsive site in 2026 is measured, not eyeballed. The three Core Web Vitals Google uses as ranking signals are specific and testable:
- Largest Contentful Paint (LCP) — how long until the largest visible element renders. Target under 2.5 seconds. The usual mobile culprits are unoptimized hero images and render-blocking fonts.
- Interaction to Next Paint (INP) — how responsive the page is to actual input, replacing the older First Input Delay metric. Target under 200ms. Heavy client-side JavaScript on a low-end mobile CPU is the typical cause of a bad score here.
- Cumulative Layout Shift (CLS) — how much visible content jumps around as the page loads. Target under 0.1. Images and ads without reserved dimensions are the most common cause.
Lighthouse and Chrome’s field data (the CrUX report) measure all three directly, on real device performance profiles, which is a meaningfully different exercise from resizing a desktop browser window and calling it mobile testing.
Test on real devices, not a resized window
A desktop browser at a narrow width is not a mobile device: it doesn’t share a low-end phone’s CPU throttling, memory limits, or touch-target behavior. A layout that looks fine in a resized Chrome window can still have tap targets too small for a thumb, or JavaScript that’s fast on a desktop CPU and sluggish on a three-year-old mid-range phone. Chrome DevTools’ device emulation with CPU and network throttling enabled gets close; testing on at least one actual low-end Android device and one actual iPhone catches what emulation still misses, particularly around touch behavior and real-world network conditions.
What “perfect” means now
The old checklist — don’t hide content, keep tap targets reasonable, watch
your image weight — is still correct, it just wasn’t sufficient. What’s
different is that CSS now has native tools (clamp(), container queries,
grid) that eliminate most of the breakpoint-patching the old approach
needed, and there’s an objective, measured definition of “responsive done
well”: specific Core Web Vitals thresholds, tested against real devices,
not a design that merely rearranges itself at three arbitrary widths and
calls it done.
Originally published in 2015 and updated for 2026.
30 minutes with a senior engineer.
Tell us what you're building. You'll leave with an honest opinion, even if it's "you don't need us."
Reference calls with past clients are available under NDA during evaluation.