Complete Guide to CSS Container Queries

Quick Answer

A CSS container query styles an element based on the size or computed styles of an ancestor container instead of the viewport. Declare a parent with container-type: inline-size, then write rules inside @container (min-width: 400px) {…}. Components become responsive to the space they actually occupy — reusable across sidebars, grids, and hero sections without writing extra media queries.

For over a decade, web developers relied exclusively on media queries to build responsive layouts. Media queries respond to the viewport — the overall browser window size — and that works well when you control every pixel of a page layout. But modern web development revolves around components: self-contained, reusable pieces of UI that can be dropped into any context. A card component might appear in a three-column grid, a narrow sidebar, or a full-width hero section, and in each case it needs to adapt to its container, not the viewport. CSS container queries solve this problem by letting you write styles that respond to the dimensions of a parent element rather than the browser window. The feature is formally specified in CSS Containment Module Level 3 and reached Baseline Widely Available status in 2024.

Container queries represent the single most impactful addition to CSS since Flexbox. They close a gap that developers have worked around for years using JavaScript-based resize observers, element query polyfills, and convoluted class-toggling schemes. With native container queries, a component can declare its own responsive breakpoints, making it truly portable across layouts, design systems, and even entirely different projects. The result is cleaner code, better performance, and a development model that matches the way we actually think about components.

This guide covers everything you need to know about container queries: from the foundational concepts of containment to advanced techniques like style queries and nested containers. By the end, you will have a thorough understanding of the API surface, practical patterns you can apply immediately, and awareness of the performance characteristics and browser support landscape. For the canonical property reference, see MDN: CSS container queries.

Understanding Containment: The Foundation

Before you can query a container, you must establish one. Container queries build on the CSS Containment specification, which lets the browser optimize rendering by isolating parts of the DOM. When you declare an element as a container, you are telling the browser that its children should be laid out independently, enabling the browser to evaluate container query conditions without triggering unbounded layout recalculations.

The key property is container-type, which accepts three values:

/* Establish a container that can be queried by width */
.card-wrapper {
  container-type: inline-size;
}

/* Establish a container queryable by both width and height */
.dashboard-panel {
  container-type: size;
}

Setting container-type: inline-size implicitly applies layout, style, and inline-size containment to the element. This means the element cannot derive its inline size from its children — it must have a size determined by its own context (a grid track, a flex basis, an explicit width, and so on). In practice this is rarely a problem because container elements are almost always sized by their parent layout, but it is important to understand if you encounter unexpected sizing behavior.

Naming Containers with container-name

When you have multiple nested containers, you need a way to specify which one a given query should target. The container-name property assigns one or more names to a container, and you can reference those names in your @container rules.

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

.main-content {
  container-type: inline-size;
  container-name: main;
}

/* Query specifically the sidebar container */
@container sidebar (max-width: 300px) {
  .widget-title {
    font-size: 0.875rem;
  }
}

If you omit the container name from an @container rule, the browser walks up the DOM tree and finds the nearest ancestor that is a size container. Naming containers makes your code more explicit and avoids ambiguity when components are nested inside multiple containers.

You can also use the shorthand container property, which combines the name and type:

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

Writing @container Rules

The @container at-rule is the core syntax for container queries. It looks similar to a media query but evaluates against a container element rather than the viewport. You can use the same range of conditions you are accustomed to from media queries, including min-width, max-width, min-height, max-height, and the newer range syntax.

/* Traditional syntax */
@container (min-width: 400px) {
  .card {
    display: grid;
    grid-template-columns: 200px 1fr;
  }
}

@container (max-width: 399px) {
  .card {
    display: flex;
    flex-direction: column;
  }
}

/* Modern range syntax */
@container (width >= 400px) {
  .card {
    grid-template-columns: 200px 1fr;
  }
}

/* Combining conditions */
@container (width >= 400px) and (width < 800px) {
  .card {
    grid-template-columns: 1fr 1fr;
  }
}

The selectors inside an @container block match elements that are descendants of the matching container. This is a critical distinction: the container itself cannot be the target of its own container query. You style the container's children, not the container.

Container Query Length Units

Container queries introduce a family of new length units that are relative to the container's dimensions, analogous to viewport units (vw, vh) but scoped to the container:

These units let you create fluid sizing that scales with the container rather than the viewport. For example, you can create text that scales proportionally within a component:

.card-title {
  font-size: clamp(1rem, 4cqi, 2rem);
}

Style Queries

Beyond size-based queries, the specification includes style queries that let you conditionally apply styles based on the computed value of custom properties on a container. Style queries use the style() function inside an @container rule.

.card-wrapper {
  --theme: light;
}

@container style(--theme: dark) {
  .card {
    background: #1a1a2e;
    color: #e0e0e0;
  }
  .card-title {
    color: #ffffff;
  }
}

@container style(--theme: light) {
  .card {
    background: #ffffff;
    color: #333333;
  }
}

Style queries are particularly powerful for theming, feature flags, and variant systems. You can set a custom property on a parent element — perhaps toggled by a class or even a data attribute — and every descendant component automatically adapts without any additional class management. As of early 2026, style queries for custom properties are supported in Chrome 111+, Edge 111+, and Safari 18+. Firefox shipped support in version 128, released in mid-2024, so style queries now work in every evergreen browser.

Practical Pattern: Responsive Card Component

The most common use case for container queries is a card that adapts from a vertical stack in narrow contexts to a horizontal layout in wider ones. Here is a complete example:

<div class="card-container">
  <article class="card">
    <img src="thumbnail.jpg" alt="Article thumbnail" class="card-image">
    <div class="card-body">
      <h3 class="card-title">Article Title</h3>
      <p class="card-excerpt">A short description of the article content.</p>
      <a href="#" class="card-link">Read more</a>
    </div>
  </article>
</div>

<style>
.card-container {
  container: card / inline-size;
}

.card {
  display: flex;
  flex-direction: column;
  border: 1px solid #e0e0e0;
  border-radius: 8px;
  overflow: hidden;
}

.card-image {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
}

@container card (width >= 500px) {
  .card {
    flex-direction: row;
  }
  .card-image {
    width: 40%;
    aspect-ratio: auto;
  }
  .card-body {
    padding: 1.5rem;
    display: flex;
    flex-direction: column;
    justify-content: center;
  }
}

@container card (width >= 800px) {
  .card-title {
    font-size: 1.5rem;
  }
  .card-excerpt {
    font-size: 1.1rem;
    line-height: 1.6;
  }
}
</style>

This card now adapts to any container it is placed in. Put it in a narrow sidebar, and it stacks vertically. Place it in a wide main content area, and it flows horizontally. Drop it into a responsive grid, and it adapts to each grid track width as the grid changes. No media queries needed, no JavaScript, and the component is entirely self-contained.

Practical Pattern: Sidebar Widget

Sidebar widgets often need to collapse from a detailed layout into a compact one when the sidebar narrows. Container queries let the widget handle this internally:

.sidebar {
  container: sidebar / inline-size;
}

.widget {
  padding: 1rem;
}

.widget-stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1rem;
}

@container sidebar (max-width: 250px) {
  .widget-stats {
    grid-template-columns: 1fr;
  }
  .widget-description {
    display: none;
  }
  .widget-title {
    font-size: 0.875rem;
  }
}

Practical Pattern: Dashboard Panel

Dashboard layouts are a prime use case for container queries because panels can be rearranged, resized, or even made resizable by the user. A panel that uses container-type: size can respond to both width and height changes:

.dashboard-panel {
  container: panel / size;
  resize: both;
  overflow: auto;
}

@container panel (width < 300px) {
  .panel-chart {
    display: none;
  }
  .panel-summary {
    font-size: 0.8rem;
  }
}

@container panel (height < 200px) {
  .panel-footer {
    display: none;
  }
  .panel-body {
    padding: 0.5rem;
  }
}

Nesting Containers

Container queries support nesting. You can have a page-level container, a section-level container inside it, and a component-level container inside that. Each @container rule resolves to the nearest matching ancestor container, or you can use named containers to target a specific level.

This is powerful for design systems where a page layout component might set a broad context, a region component refines it, and an individual widget adapts based on its immediate surroundings. However, be deliberate about where you establish containers. Every container introduces containment, and excessive containment can make debugging layout issues more difficult.

A practical rule of thumb: establish containers at the level where the element's width is determined by a layout algorithm (grid tracks, flex items with defined basis, percentage-width wrappers) rather than by content. This ensures the containment does not conflict with the sizing model.

Performance Considerations

Container queries are designed to be performant. The containment requirement is not arbitrary — it is what makes the feature fast. Because a container's inline size cannot depend on its descendants, the browser can determine the container size in a single layout pass and then evaluate query conditions without circular dependencies.

That said, there are a few things to keep in mind:

In real-world benchmarks, container queries perform comparably to media queries. The primary cost is establishing containment, and that cost is paid once during layout. The query evaluation itself is negligible.

Migration from Media Queries

You do not need to replace all media queries with container queries. Media queries remain the right tool for page-level layout decisions: when to switch from a single-column to a multi-column layout, when to show or hide a navigation drawer, or when to adjust the overall page spacing. Container queries complement media queries by handling component-level responsiveness.

A practical migration strategy is to identify components that appear in multiple layout contexts. If a component currently has media query breakpoints that are tightly coupled to a specific page layout, those are candidates for conversion to container queries. Components that only ever appear in one context can keep their media queries without issue.

Browser Support

Container size queries enjoy broad support across modern browsers:

Style queries shipped later but are now broadly available: Chrome 111+, Safari 18+, and Firefox 128+. Container size queries reached the Baseline Widely Available tier on web.dev in 2024, meaning the feature has been interoperable across all major browsers for at least 30 months. For style queries you can still apply progressive enhancement, but in 2026 the safest assumption is that any user on an evergreen browser will get the full feature set.

For projects that must support older browsers, you can use @supports (container-type: inline-size) as a feature query to provide fallback styles. The component rendering without container queries should be acceptable (typically a single-column or mobile-first layout).

Common Pitfalls

Several issues trip up developers who are new to container queries:

Frequently Asked Questions

What is a CSS container query?

A CSS container query lets you apply styles to an element based on the size or computed styles of an ancestor container, rather than the viewport. You declare the parent as a container with container-type: inline-size, then write rules inside @container (min-width: 400px) {…}. This makes a single component behave responsively in any layout it is dropped into.

How is @container different from @media?

@media evaluates against the viewport and is best for page-level layout decisions (single-column vs multi-column page, navigation drawer, global spacing). @container evaluates against the nearest ancestor query container and is designed for component-level responsiveness, so the same card or sidebar widget can adapt automatically wherever it is used.

Do container queries work in all modern browsers?

Yes. Size container queries are supported in Chrome and Edge 105+, Safari 16+, and Firefox 110+, and reached Baseline Widely Available in 2024. Style queries for custom properties also work in all evergreen browsers as of mid-2024.

What does container-type: inline-size do?

It establishes the element as a query container that can be queried by its inline dimension (width in horizontal writing modes). Behind the scenes it applies layout, style, and inline-size containment, which lets the browser evaluate @container rules in a single pass without circular dependencies.

Can I query a container's height?

Yes, but you must use container-type: size instead of inline-size. Full size containment applies in both dimensions, which prevents the container from deriving its height from its children. Use this only when you genuinely need height-based queries, such as in user-resizable dashboard panels.

Should I replace all my media queries with container queries?

No. Use media queries for page-level layout decisions and container queries for component-level responsiveness. Many projects benefit from both: a top-level grid switches columns with @media, while individual cards inside that grid adapt with @container.

Further Reading

Container queries are transformative, and hands-on experimentation is the best way to build confidence with them. Try our Container Query Generator tool to visually build and test container query rules, then export the CSS for your projects.

External references: MDN — CSS container queries · W3C — CSS Containment Module Level 3 · web.dev — Baseline Widely Available 2024.

For more CSS guides and tools, visit the guides index or explore the full collection of tools on the Modern CSS Tools homepage.