5 min read

Container Queries vs Media Queries: When to Use Each (With Code)

You've heard container queries are the future of responsive CSS. You've also got a codebase full of media queries that work fine. Do you rip them all out? Spoiler: no. The two aren't competing — they solve different problems, and knowing which one to reach for is the actual skill.

Here's the honest breakdown: what each one does, when to use which, and how to combine them without overcomplicating your CSS.

The one-sentence difference

A media query asks: "How big is the browser?" A container query asks: "How big is my parent?"

That's the whole thing. Media queries respond to the viewport — the window you're viewing the page in. Container queries respond to the element that contains the component you're styling.

When media queries are still the right tool

Media queries are for page-level layout. The sidebar that collapses on mobile, the nav that turns into a hamburger menu, the hero that stacks on small screens — these respond to the overall page width, so the viewport is the correct signal.

/* Page-level: this is what media queries are for */
@media (max-width: 768px) {
  .layout {
    grid-template-columns: 1fr;
  }
  .nav {
    display: none; /* swap to hamburger */
  }
}

These styles genuinely depend on the browser width. There's no container that "owns" the whole page. Media queries are correct here, and trying to replace them with container queries would be wrong.

When container queries are the answer

Container queries are for reusable components — the pieces that get dropped into different contexts and need to adapt to the space they're given. A product card, a stat widget, a form field, a modal. If the same component can live in a narrow sidebar and a wide content area, the viewport is the wrong signal to respond to.

/* The parent is the source of truth */
.stats-grid {
  container: stats / inline-size;
}

/* This card adapts to ITS width, not the browser's */
@container stats (min-width: 300px) {
  .stat-card {
    flex-direction: row;
  }
}

The card in a 200px sidebar column stacks. The same card in a 400px content area goes horizontal. The exact same CSS, zero overrides, because the query targets the container, not the viewport.

The decision rule that actually works

Stop debating frameworks and use this checklist instead:

  • Does the element change because the page changes? → media query.
  • Does the element change because its parent changes? → container query.
  • Is it a reusable component that appears in multiple contexts? → container query.
  • Is it a one-off layout section (hero, nav, footer)? → media query.

The rule of thumb: layout responds to the viewport, components respond to their container. Mixing them this way isn't messy — it's exactly what both features were designed for.

Combining both, the practical way

Most real pages end up with both, and that's fine. Here's a realistic pattern:

/* Page-level: media query controls the grid */
@media (max-width: 900px) {
  .dashboard {
    grid-template-columns: 1fr; /* sidebar drops below */
  }
}

/* Component-level: container query controls the cards */
.dashboard {
  container: dash / inline-size;
}
@container dash (min-width: 400px) {
  .stat-card { flex-direction: row; }
}

The media query decides how the page's big sections stack; the container query decides how the cards inside each section adapt to the space that decision gives them. Each query works on the layer it understands.

A warning about nesting

Once you start using container queries, you'll create nested containers without noticing. A card inside a grid inside a section — three potential containers. A bare @container matches the nearest ancestor container, so name yours once you're more than one level deep:

.section  { container: section / inline-size; }
.card-grid { container: grid / inline-size; }

@container grid (min-width: 400px) {
  /* only the card-grid container */
}

Where to go deeper

This article covers the decision between the two. For the full mechanics — container-type options, container query units like cqi and cqw, the gotchas with containment, and a complete worked example — read the deep dive: CSS Container Queries: The Practical Guide With Real Examples.

And when your CSS starts growing a library of component patterns worth keeping, Snippet Ark is a good home for them — save the card pattern, tag it, and pull it out next project instead of rewriting it.

The bottom line

Don't replace your media queries. Replace the misuse of them. Keep media queries for the page, adopt container queries for your components, and your CSS will finally stop breaking every time someone moves a card to a different part of the layout. Both tools have a job — now you know which one is which.