EdgeCases Logo
Feb 2026
CSS
Deep
7 min read

CSS Container Queries Edge Cases: When @container Silently Fails

Container queries are here, but containment types and the ancestor lookup algorithm create subtle traps. Here's what breaks and how to fix it.

css
container-queries
containment
responsive-design
layout
edge-case

Container queries shipped. You're finally styling components based on their container, not the viewport. But then things break: nested containers ignore your queries, elements collapse to zero height, or query units resolve to viewport sizes instead of container sizes. The culprit? Containment types and the lookup algorithm—here's what trips up most teams adopting @container.

The Containment Type Trap

The first gotcha: container-type determines which dimensions you can query. Pick wrong, and your queries silently fail:

/* ❌ This query NEVER matches */
.sidebar {
  container-type: inline-size; /* Only inline (width) queryable */
}

@container (height > 500px) {
  .card { padding: 2rem; } /* Ignored—height not tracked */
}

/* ✅ Use 'size' to query both axes */
.sidebar {
  container-type: size; /* Both width AND height queryable */
}

@container (height > 500px) {
  .card { padding: 2rem; } /* Now this works */
}

inline-size only establishes containment on the inline axis (width in horizontal writing modes). Height queries require container-type: size.

Why inline-size Is the Default

Most examples use inline-size because size containment has a critical side effect—it breaks intrinsic height:

/* container-type: size creates height containment */
.container {
  container-type: size;
}

/* Problem: Children no longer contribute to parent height */
<div class="container">
  <p>This text doesn't affect container height</p>
  <p>Container collapses to 0px unless you set explicit height</p>
</div>

/* You MUST set an explicit height */
.container {
  container-type: size;
  height: 400px; /* Required for size containment */
}

Size containment means the element's size is determined independently of its contents. If you don't set a height, it collapses. Use inline-size unless you specifically need to query height.

The Nearest Ancestor Rule

Container queries target the nearest ancestor with containment—not necessarily the one you intended:

<section class="page">         <!-- container-type: inline-size -->
  <div class="sidebar">        <!-- container-type: inline-size -->
    <article class="card">     <!-- Queries target .sidebar, not .page! -->
    </article>
  </div>
</section>

/* This queries .sidebar, the nearest container */
@container (width > 800px) {
  .card { grid-template-columns: 1fr 1fr; }
}

/* .sidebar is 300px, so this never matches—
   even though .page is 1200px */

The fix: use named containers to target specific ancestors:

.page {
  container-type: inline-size;
  container-name: page;
}

.sidebar {
  container-type: inline-size;
  container-name: sidebar;
}

/* Explicitly query the page container */
@container page (width > 800px) {
  .card { /* Styles for when PAGE is wide */ }
}

/* Or query the sidebar */
@container sidebar (width > 200px) {
  .card { /* Styles for when SIDEBAR is wide */ }
}

Container Query Units Fallback

Container query units (cqw, cqh, cqi, cqb) are powerful—but they have a surprising fallback:

.element {
  font-size: 5cqi; /* 5% of container inline size */
}

/* If NO container exists up the tree...
   cqi falls back to svw (small viewport width)
   cqb falls back to svh (small viewport height) */

This means query units work outside container contexts—but they become viewport-relative. If your component is supposed to be self-contained, this fallback can break layouts:

/* Defensive pattern: ensure a container exists */
.component-wrapper {
  container-type: inline-size;
}

.component-content {
  /* Now cqi definitely refers to .component-wrapper */
  padding: 2cqi;
}

Can't Query Your Own Container

A common mistake: trying to apply container-queried styles to the container itself:

.card {
  container-type: inline-size;
}

/* ❌ This doesn't work */
@container (width > 400px) {
  .card { /* Styles for the container itself */ }
}

/* The query selects .card's CHILDREN based on .card's size
   You cannot style .card itself with its own container query */

/* ✅ Fix: Add a wrapper or style children */
<div class="card-container">  <!-- container-type here -->
  <div class="card">          <!-- style this -->
  </div>
</div>

.card-container { container-type: inline-size; }

@container (width > 400px) {
  .card { /* Now this works */ }
}

Containment Breaks Certain Layouts

Container queries require CSS containment, which isolates the element from layout calculations. This breaks:

  • Sticky positioning inside containersposition: sticky may not work as expected
  • Percentage heights — Height containment (size) breaks height: 100% chains
  • Margin collapse — Containment creates a new block formatting context, preventing margin collapse
  • Baseline alignment — Grid/flex baseline alignment can break with contained children
/* ❌ Sticky header inside container may fail */
.container {
  container-type: inline-size;
}

.sticky-header {
  position: sticky;
  top: 0;
  /* May not stick correctly depending on containment */
}

/* Test sticky behavior after adding container-type */

Style Queries: The Forgotten Sibling

Container queries aren't just for size. Style queries let you respond to custom property values:

.theme-provider {
  --theme: dark;
}

/* Query the computed custom property value */
@container style(--theme: dark) {
  .card {
    background: #1a1a1a;
    color: white;
  }
}

/* No container-type needed for style queries—
   any element can be queried for style values */

Style queries don't require container-type declarations. Every element is implicitly a style query container. This is useful for theme switching without adding class names everywhere.

The Shorthand Syntax

Use the container shorthand to set both name and type:

/* Longhand */
.element {
  container-name: sidebar;
  container-type: inline-size;
}

/* Shorthand: name / type */
.element {
  container: sidebar / inline-size;
}

/* Type-only (anonymous container) */
.element {
  container-type: inline-size;
}

Debugging Container Queries

Chrome DevTools has container query debugging:

  • Elements panel shows container badges on elements with container-type
  • Click the badge to see container dimensions
  • Styles panel shows which @container rules match/don't match
  • Hover over @container rules to highlight the matched container

If your query isn't matching, check:

  1. Is there a container ancestor with the correct container-type?
  2. Are you querying the right axis (width vs height)?
  3. Is another container closer in the ancestor chain intercepting?
  4. If using a name, does it match exactly?

Key Takeaways

  • inline-size only queries width; use size for height queries
  • size containment collapses height—set explicit dimensions
  • Queries target the nearest container ancestor; use names to be explicit
  • Query units (cqi, etc.) fall back to viewport units without a container
  • You can't style a container based on its own size—only its children
  • Containment affects sticky positioning, margins, and baseline alignment
  • Style queries work without container-type

Advertisement

Related Insights

Explore related edge cases and patterns

CSS
Surface
CSS text-wrap: balance and pretty
6 min
CSS
Surface
CSS contain: Render Isolation for Performance
6 min

Advertisement