CSS Container Queries

Build truly responsive components that adapt to their container size, not just the viewport. Covers container query syntax, use cases vs media queries, component-driven responsive design, and the patterns that make components reusable across any layout context.

CSS container queries enable responsive design based on the size and layout of a container element, rather than the viewport. They are essential when components must adapt independently across varying parent layouts—such as a card that resizes its columns based on its container’s width, regardless of screen size. Use container queries when you need layout logic that scales with the component’s immediate context, not just the browser window.

Defining a Container Query

To define a container query, you declare a container using container-type, then apply @container rules with media-like conditions. The container becomes a context for its children’s styles.

.card {
  container-type: inline-size; /* or block-size, strict, or any */
}

@container (min-width: 30rem) {
  .card {
    font-size: 1.25rem;
    padding: 1.5rem;
  }
}

The container-type property sets the container’s sizing behavior:

A container is any element that has container-type applied. It does not need to be a <div> or display: container. A <section>, <article>, or even a <figure> can be a container.

Controlling Container Size and Scope

The container’s size is determined by its content and parent layout. It updates during layout and triggers re-evaluation of container queries.

To control how the container size is computed, use container-name to assign a named scope.

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

@container hero-container (min-width: 48rem) {
  .hero-title {
    font-size: 3rem;
  }
}

Multiple containers can coexist in a page. Each container’s size is independently tracked, and queries can target specific containers by name.

Container Query Breakpoints

Breakpoints in container queries work like media queries but are resolved per container.

@container (min-width: 30rem) {
  .card {
    grid-template-columns: 1fr;
  }
}

@container (min-width: 48rem) {
  .card {
    grid-template-columns: 1fr 1fr;
  }
}

@container (min-width: 64rem) {
  .card {
    grid-template-columns: 1fr 1fr 1fr;
  }
}

Breakpoints are evaluated at layout time. A container query triggers a style update when its size crosses a breakpoint threshold. The query condition can use any valid CSS value, including min-width, max-width, min-height, max-height, width, height, aspect-ratio, and any/all combinations.

Using any and all for Complex Conditions

The any and all keywords allow combining multiple conditions.

@container (any (min-width: 30rem, max-width: 60rem)) {
  .card {
    background-color: var(--accent);
  }
}

@container (all (min-width: 30rem, min-height: 20rem)) {
  .card {
    border-radius: 1rem;
  }
}

any evaluates to true if any condition is met. all requires all conditions to be true. These keywords are evaluated at query resolution time, not at paint time.

Practical Usage Patterns

Responsive Cards in Grids

A common use case is a grid of cards that adapt to their container’s width.

.card-container {
  container-type: inline-size;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 1rem;
}

@container (min-width: 30rem) {
  .card {
    padding: 1.25rem;
  }
}

@container (min-width: 48rem) {
  .card {
    padding: 1.5rem;
    font-size: 1.1rem;
  }
}

@container (min-width: 64rem) {
  .card {
    padding: 2rem;
    font-size: 1.25rem;
  }
}

Each card adjusts its layout independently of the viewport. A 3-column grid on a wide screen can have cards that are 30rem wide, but a narrow sidebar might hold cards that are only 25rem wide—each card’s styles update based on its own width.

Nested Container Queries

Containers can be nested, and queries can be applied at different levels.

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

@container (min-width: 48rem) {
  .article {
    font-size: 1.125rem;
  }
}

.article .figure {
  container-type: inline-size;
}

@container (min-width: 30rem) {
  .figure img {
    width: 100%;
  }
}

@container (min-width: 48rem) {
  .figure img {
    width: 80%;
  }
}

The .figure element becomes a container for its image. The image’s styles depend on the figure’s width, which might vary independently of the article’s width.

Dynamic Layouts with JavaScript

CSS container queries can be complemented with JavaScript for fine-grained control.

const container = document.querySelector('.card');
container.style.containerType = 'inline-size';
container.style.containerName = 'card-container';

// Trigger a manual layout update
container.style.containerType = 'inline-size'; // forces re-evaluation

The containerType and containerName properties on the DOM element are live. Changing them triggers a re-evaluation of all container queries targeting that container.

Common Pitfalls and Silent Failures

Container Size Not Updating

A common failure is that a container’s size does not trigger query updates. This happens when:

To fix this, ensure the container is part of the layout flow. If a container is display: inline, its inline-size is not automatically updated. Use container-type: inline-size and ensure the container participates in layout.

Query Conditions Misinterpreted

Developers often assume min-width: 30rem means “width ≥ 30rem,” but it evaluates at layout time. A container that is 29.9rem wide, even if it has min-width: 30rem, does not trigger the query. The evaluation is based on the computed size at layout, not the viewport width.

The container-size property can be used to debug this:

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

.card::before {
  content: 'Container width: ' attr(data-size) 'rem';
  display: block;
  font-size: 0.75em;
  color: #666;
}

@container (min-width: 30rem) {
  .card::before {
    color: #000;
    font-weight: bold;
  }
}

This shows the container’s size and helps catch timing issues.

Overlapping and Conflicting Queries

Multiple queries targeting the same container can conflict. For example:

@container (min-width: 30rem) {
  .card {
    font-size: 1.1rem;
  }
}

@container (min-width: 30rem) and (max-width: 48rem) {
  .card {
    font-size: 1.2rem;
  }
}

@container (min-width: 48rem) {
  .card {
    font-size: 1.3rem;
  }
}

The second query takes precedence when the container is between 30rem and 48rem wide. But if the container grows beyond 48rem, both the min-width: 48rem and the min-width: 30rem queries apply. The second rule overrides the first, but the min-width: 30rem rule does not deactivate.

Use container-size or container-type to observe the active queries.

Misunderstanding strict and size

container-type: strict means the container’s size is fixed after layout and does not change during the layout pass. This is useful when you want the container to be a stable context, regardless of content changes.

.container {
  container-type: strict;
  container-name: sidebar;
}

@container sidebar (min-width: 25rem) {
  .sidebar-nav {
    display: block;
  }
}

@container sidebar (min-width: 30rem) {
  .sidebar-nav {
    display: flex;
  }
}

With strict, the container’s size is measured once and used for all queries. If the content grows and the container expands, the min-width query does not trigger until the next layout pass.

container-type: size combines inline-size and block-size, making the container responsive to both dimensions.

Advanced Techniques

Querying Multiple Properties Simultaneously

You can combine multiple conditions using parentheses and logical operators.

@container (min-width: 30rem) and (aspect-ratio: 1.5) {
  .card {
    background-image: url('/hero-landscape.jpg');
  }
}

@container (min-width: 48rem) or (max-height: 40rem) {
  .card {
    border: 1px solid #ccc;
  }
}

These conditions are evaluated independently and combined using and, or, and not.

Using Container Queries with CSS Custom Properties

Container queries are ideal with CSS custom properties.

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

@container (min-width: 30rem) {
  :root {
    --card-padding: 1.25rem;
    --card-font-size: 1.1rem;
  }
}

@container (min-width: 48rem) {
  :root {
    --card-padding: 1.5rem;
    --card-font-size: 1.25rem;
  }
}

.card {
  padding: var(--card-padding);
  font-size: var(--card-font-size);
}

This pattern lets you define a full design system per container size, with properties shared across components.

Resetting Container Queries

To reset a container’s query state, use container-type with no value.

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

.card.reset {
  container-type: none;
}

Setting container-type: none resets the container to its initial state, causing all container queries to re-evaluate from scratch.

Summary

Container queries shift the foundation of responsive design from viewport-centric to component-centric. They allow elements to adapt not just to screen size, but to their own container’s layout. Use container-type to define the container’s measurement behavior, @container to write responsive rules, and container-name to scope queries across multiple containers. Pay attention to layout timing: a container’s size must be computed before its queries are evaluated. Use any and all for complex logic, and combine container queries with JavaScript for dynamic behavior. The key insight is that a container query is not just a CSS rule—it is a responsive unit of layout that can be composed and reused across a site.

This page was rewritten on 18 October 2026. It replaced a templated version that was not specific to its own title. How these pages are written and checked. If anything here is wrong, tell us at [email protected] and we will correct it.