The Problem: You're Probably Using Container Queries Wrong

CSS container queries are not new. Browser support sits around 94%, yet the State of CSS survey reports that while 86% of developers know about them, only 41.4% actually use them. That gap isn't laziness — it's a mental model problem.

At first glance, @container looks identical to @media. Same syntax shape, same min-width condition. So developers assume they work the same way, apply them to the same problems, and then wonder why their components still break inside a sidebar.

They break because media queries look outward at the viewport, and container queries look inward at the component's parent.

Consider a .card placed in a 300px grid cell on a 1920px desktop. A @media (min-width: 1024px) rule fires — the viewport is 1920px — but the card only has 300px to work with. The layout deforms, overflows, or cramps. The media query did its job. The reference point was just wrong.

This guide walks through the correct mental model, working code for three real scenarios, and the side effects nobody warns you about. For a broader look at where CSS is heading in 2026, see our breakdown of the CSS Alpha function, Grid Lanes, and CSS Day highlights.

Developer comparing CSS container queries and media queries on a code editor screen IT Technology Image

The Core Mental Model: Macro vs. Micro Layouts

ConcernUse @mediaUse @container
Page structure, header, footer✅❌
Main grid layout✅❌
System preferences (prefers-color-scheme)✅❌
Device capabilities (touch, hover)✅❌
Cards, widgets, forms❌✅
Navigation inside a component❌✅
Anything reused in multiple contexts❌✅

Rule of thumb: media queries are for the page, container queries are for the component. An element shouldn't become "tablet-sized" because the viewport crossed 768px — it should switch layout when it has enough room, whether that's on mobile or inside a desktop sidebar.

Example 1: A Card That Responds to Its Own Space

/* Register the wrapper as a container — note: the container CANNOT query itself */
.card-wrapper {
  container-name: card;
  container-type: inline-size;
}

/* Default: stacked layout */
.card {
  display: flex;
  flex-direction: column;
  background: #f4f4f4;
}

/* When the wrapper has at least 450px of inline space, go horizontal */
@container card (min-width: 450px) {
  .card {
    flex-direction: row;
    align-items: center;
  }
}

Example 2: Fluid Typography That Scales With the Component

Media-query-based fluid type uses vw units — relative to the viewport. Move that component into a sidebar and the type becomes wrong.

/* ❌ Viewport-relative — breaks inside a sidebar */
.card-title {
  font-size: clamp(100%, 1rem + 2vw, 24px);
}

/* ✅ Container-relative — scales with the component */
.card-title {
  font-size: clamp(1rem, .5rem + 3cqi, 2rem);
}

cqi is the container inline-size unit. Pair it with clamp() and the typography becomes fully self-contained.

Example 3: Detecting Flexbox Wrap Without JavaScript

CSS can't detect when flex items wrap — there's no :wrapped pseudo-class. But you can nest a container query inside a flex item to simulate it:

.flex-layout {
  display: flex;
  flex-wrap: wrap;
}

/* Each item is its own container */
.flex-item {
  container-type: inline-size;
  flex: 1 1 390px; /* grow to fill, wrap below 390px */
}

.card {
  display: flex;
  flex-direction: column;
  background: #f4f4f4;
}

/* When the wrapped item stretches to fill the row, this fires */
@container (min-width: 600px) {
  .card {
    flex-direction: row;
    align-items: center;
    background: #e2f0d9;
  }
}

When items wrap, flex-grow: 1 stretches them across the row. That width expansion triggers the container query — no ResizeObserver required.

Responsive card component adapting to container width using CSS container queries System Abstract Visual

Three Side Effects That Will Bite You

1. A Container Cannot Query Itself

This is the most common mistake:

/* ❌ DOES NOT WORK — infinite loop */
.card {
  container-name: card;
  container-type: inline-size;
}

@container card (min-width: 400px) {
  .card { display: flex; } /* querying the container to restyle the container */
}

You need a wrapper element so the styled element is a descendant of the container. That's the extra DOM node nobody mentions in the announcement post.

2. Querying Block Size Can Collapse Your Layout

/* ❌ Collapses to 0px if no explicit height is set */
.hero-banner {
  container-type: size; /* queries BOTH inline and block size */
}

The browser calculates container dimensions without looking at children. With no height, min-height, or aspect-ratio, the container becomes 0px tall. Prefer container-type: inline-size unless you genuinely need block-size queries.

3. No Custom Properties in Query Conditions

:root { --breakpoint-lg: 1600px; }

/* ❌ DOES NOT WORK */
@container (min-width: var(--breakpoint-lg)) { }

Custom properties cascade, and a query could theoretically change the value it's querying against. The spec forbids it. You'll have to hardcode breakpoints or use a preprocessor.

When to Reach for Which

  • Container queries: the component is reused in multiple layout contexts (full-width grid and sidebar).
  • Media queries: the component only exists at page level (top nav, footer) and the viewport is a reliable reference.
  • Both: a page-level media query sets the macro grid, and container queries handle each cell's internals.

If you're building component-driven architectures where teams own their own UI slices, container queries pair naturally with vertical microfrontends on Cloudflare — each team's component adapts to whatever slot the host layout gives it.

Web developer workspace with browser devtools inspecting container query layout Software Concept Art

The Bottom Line

Container queries look like media queries because of familiarity, not because they're equivalent. The syntax is similar; the semantics are inverted. Media queries ask "how big is the screen?" Container queries ask "how much room do I have right here, right now?"

With over 2,300 unique viewport sizes in the modern web, viewport-based responsiveness is a proxy that increasingly fails. Component-level responsiveness is the correct abstraction — but only if you stop reaching for @container as a drop-in @media replacement.

Next steps to level up:

  1. Audit your components — anything reused in two or more layout contexts is a container query candidate.
  2. Migrate fluid typography from vw to cqi units where components are context-agnostic.
  3. Explore container style queries (still experimental) for responding to computed styles, not just size.
  4. Watch the flex-wrap detection pattern — it's a JavaScript-free way to handle layout state changes that used to require ResizeObserver.

Further reading: Stop treating CSS container queries like traditional media queries — the source analysis this guide is built on.

This content was drafted using AI tools based on reliable sources, and has been reviewed by our editorial team before publication. It is not intended to replace professional advice.