CSS / UI

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 preferencesprefers-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.

Found this useful?

Share

I post shorter takes on css, ui & design and frontend leadership on LinkedIn — follow along there, or get in touch if you're working on something related.