Skip to main content
  • Created:
  • Updated:
  • Author:
    Takeshi Takatsudo

Container Queries

The Problem

Media queries respond to the viewport width, not the width of the component's container. When a component is placed in a sidebar, a modal, or any constrained layout, viewport-based media queries cannot adapt the component's layout to its actual available space. AI agents almost always reach for @media queries for component-level responsiveness, ignoring container queries entirely.

The Solution

CSS Container Queries (@container) allow components to respond to the size of their parent container rather than the viewport. This makes components truly reusable across different layout contexts. Container queries are Baseline 2023 and supported in all modern browsers.

Setting Up a Container

A parent element must be declared as a containment context using container-type. The most common value is inline-size, which enables queries based on the container's inline (horizontal) dimension.

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

Querying the Container

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

Basic Container Query

The iframe in this demo acts as the container boundary. Use the viewport buttons to see the card layout adapt to the container width.

Basic Container Query — card layout adapts to container width

Named Containers

When containers are nested, @container queries match the nearest ancestor with container-type set. To target a specific container, use container-name and reference it in the query.

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

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

/* Only responds to the sidebar container */
@container sidebar (max-width: 300px) {
.nav-list {
flex-direction: column;
}
}

The shorthand container property combines both:

.sidebar {
container: sidebar / inline-size;
}
Named Containers — same component adapts differently in sidebar vs main

Container Query Units

Container query units are relative to the dimensions of the query container. These are useful for fluid sizing within a component.

  • cqw — 1% of the container's width
  • cqh — 1% of the container's height
  • cqi — 1% of the container's inline size
  • cqb — 1% of the container's block size
  • cqmin — the smaller of cqi or cqb
  • cqmax — the larger of cqi or cqb
.card-container {
container-type: inline-size;
}

.card__title {
/* 5% of the container's inline size, clamped */
font-size: clamp(1rem, 5cqi, 2rem);
}

.card__body {
/* Padding relative to container width */
padding: 2cqi;
}
Container Query Units — text and spacing scale with container

Card Component Adapting to Container Width

A common real-world use case is a card component that works in any layout context: a narrow sidebar, a medium-width grid column, or a full-width main area.

Adaptive Card Grid — cards respond to their container, not the viewport

Container Queries vs. Media Queries

The key difference: media queries respond to the viewport, while container queries respond to the parent container. This demo places the same component in two different-width containers on the same page. The media query version looks identical in both because the viewport hasn't changed. The container query version adapts to each container independently.

Container queries vs media queries — same component, different containers

In the demo above, the @container cards adapt independently: the card in the narrow container stacks vertically while the card in the wide container goes horizontal. The @media cards both go horizontal because the viewport (the iframe) is wider than 300px — neither card knows how wide its actual container is.

Code Examples

Responsive Card Component

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

/* Base: stacked layout */
.card {
display: flex;
flex-direction: column;
}

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

/* When container is wide enough: horizontal layout */
@container card (min-width: 500px) {
.card {
flex-direction: row;
}

.card__image {
width: 200px;
aspect-ratio: 1;
}
}

/* When container is very wide: add extra spacing */
@container card (min-width: 800px) {
.card {
gap: 2rem;
padding: 2rem;
}

.card__image {
width: 300px;
}
}
.nav-wrapper {
container-type: inline-size;
container-name: nav;
}

.nav-list {
display: flex;
flex-direction: column;
gap: 0.25rem;
list-style: none;
padding: 0;
margin: 0;
}

/* Horizontal layout when container allows */
@container nav (min-width: 600px) {
.nav-list {
flex-direction: row;
gap: 1rem;
}
}

Combining Container Queries with Container Query Units

.widget-wrapper {
container: widget / inline-size;
}

.widget__title {
font-size: clamp(1rem, 5cqi, 2rem);
}

.widget__body {
padding: clamp(0.5rem, 3cqi, 1.5rem);
}

@container widget (min-width: 400px) {
.widget {
display: grid;
grid-template-columns: auto 1fr;
gap: 1rem;
}
}

Common AI Mistakes

  • Using media queries for component layouts: AI agents default to @media queries even when the component needs to adapt to its container, not the viewport.
  • Forgetting container-type: Writing @container rules without setting container-type on the parent element. The container must be explicitly declared.
  • Using container-type: size unnecessarily: Height-based containment (size) can cause layout issues. Use inline-size for the vast majority of cases.
  • Not naming nested containers: When containers are nested, omitting container-name leads to ambiguity — @container queries match the nearest ancestor container. Name containers when nesting to target specific ancestors.
  • Querying the element itself: The @container query targets the nearest ancestor with container-type set, not the element you are styling. The container and the styled element must be different elements.

When to Use

  • Component-level responsiveness: Any reusable component that may appear in different layout widths (cards, navigation, form groups).
  • Sidebar vs. main content: When the same component appears in both wide and narrow contexts on the same page.
  • Design system components: Components built for reuse across different applications and layouts.
  • Not for page-level layout: Continue using @media queries for macro layout concerns like switching between single-column and multi-column page layouts.

References