Fewer Media Queries, More Fluid CSS: A Modern Approach to Responsive Design
3 min read
Open a stylesheet from a few years ago and count the media queries. I've inherited files with twelve breakpoints — each one a hand-tuned patch for a specific device width, each one a place where the layout can break between the patches. Modern CSS offers a better deal: layouts and typography that adapt continuously, with breakpoints reserved for the few changes that are genuinely structural. Two features carry most of the weight.
The 12-media-query problem
Breakpoint-driven design treats responsiveness as a set of discrete layouts: phone, tablet, desktop, each frozen at a width someone chose in 2019. The problems compound: devices don't cluster at your breakpoints anymore (folds, split-screens, resized windows), every breakpoint doubles the states you must test, and the layout is only correct at the widths you explicitly handled. Fluid CSS inverts the model: describe the rules of the layout and let the browser solve for every width — including the ones that don't exist yet.
Grid auto-fit + minmax: layouts that solve themselves
The classic card grid, no breakpoints:
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
gap: 1.25rem;
}Read it as instructions to the browser: "columns of at least 260px, as many as fit, sharing leftover space equally." At 1200px you get four columns; at 800px, three; on a phone, one — and every width in between works too, because no width was ever special. Compare the before:
/* ❌ The old way: three arbitrary snapshots, broken between them */
.cards { display: grid; grid-template-columns: 1fr; }
@media (min-width: 640px) {
.cards { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 1024px) {
.cards { grid-template-columns: repeat(4, 1fr); }
}Three declarations replaced by one, and the one is more correct. (If the flex-vs-grid choice here is fuzzy, my 10-second rule covers it — this is 2D territory, so Grid.)
clamp(): typography that breathes
clamp(min, preferred, max) lets a value scale with the viewport between hard bounds:
h1 {
/* never below 1.75rem, never above 3rem, fluid in between */
font-size: clamp(1.75rem, 1.2rem + 2.5vw, 3rem);
}
.section {
/* fluid vertical rhythm, same idea */
padding-block: clamp(2rem, 1rem + 4vw, 5rem);
}The middle value mixes a rem base with a viewport-relative term — the rem component
matters, because a pure-vw size ignores the user's font-size preference and breaks
zoom (an accessibility failure, not a style choice). Headlines that were three
font-size breakpoints become one line that's correct at every width.
A before/after worth internalizing
A hero section, old and new:
/* Before: 3 breakpoints × 3 properties = 9 tuned values */
.hero { padding: 2rem 1rem; }
.hero h1 { font-size: 1.75rem; }
@media (min-width: 768px) {
.hero { padding: 3rem 2rem; }
.hero h1 { font-size: 2.25rem; }
}
@media (min-width: 1200px) {
.hero { padding: 5rem 4rem; }
.hero h1 { font-size: 3rem; }
}
/* After: 2 declarations, continuous, no dead zones */
.hero {
padding: clamp(2rem, 1rem + 4vw, 5rem) clamp(1rem, 4vw, 4rem);
}
.hero h1 {
font-size: clamp(1.75rem, 1.2rem + 2.5vw, 3rem);
}Less code is nice; fewer states to test is the real win. There is no width at which this hero is between designs.
When you still genuinely need a media query
Fluid techniques scale sizes; media queries change structure and behavior. Keep them for:
- Layout mode changes — sidebar becomes a drawer, horizontal nav becomes a menu button. That's not a size scaling; it's a different UI.
- Showing/hiding by context — content that shouldn't exist on small screens at all.
- User preferences —
prefers-reduced-motion,prefers-color-scheme(dark mode done right); these are media queries doing their truest job. - Container-relative decisions — though that's increasingly container queries' territory.
The end state isn't zero media queries; it's media queries that each mark a real decision. On recent projects that means three or four per app instead of twelve per file — and layouts that are simply correct everywhere in between.