Container Queries

What You'll Learn

  • How container queries enable component-based responsive design
  • The difference between container queries and media queries
  • Using container-type to define query containers
  • Applying styles with @container rules based on container size
  • Using container query units (cqi, cqw, cqh, etc.) for fluid sizing
  • Building truly reusable components that adapt to any context

Introduction to Container Queries

Container queries represent a paradigm shift in responsive design. Instead of styling components based on the viewport size (media queries), container queries let components respond to the size of their container. This enables truly reusable components that work anywhere on your page without needing to know about the overall layout.

A card component can adapt whether it's in a narrow sidebar, a medium-width grid column, or a full-width hero area—all with the same CSS. This solves the longstanding problem of components that look perfect in one context but break when reused elsewhere.

Defining a Container: container-type

Before you can query a container's size, you must explicitly make it a query container using container-type. The most common value is inline-size, which allows querying the container's width.

Syntax

.container { container-type: inline-size; /* Now descendants can query this container's width */ }

Container Type Values

/* Query inline size (usually width) - most common */ container-type: inline-size; /* Query both dimensions (width and height) */ container-type: size; /* Not a query container (default) */ container-type: normal;

Basic Container Query: @container

Once you've defined a query container, use @container rules to apply styles based on the container's size. The syntax is similar to media queries but targets the nearest ancestor container instead of the viewport.

Syntax

.card-container { container-type: inline-size; } .card { /* Default styles for narrow containers */ display: block; } @container (min-width: 400px) { .card { /* Styles when container is 400px+ wide */ display: flex; gap: 1.5rem; } }

Example

<div class="card-container"> <article class="card"> <img src="photo.jpg" alt="Card image"> <div class="card-content"> <h3>Card Title</h3> <p>Card switches from vertical to horizontal layout based on container width.</p> </div> </article> </div>

Rendered Result:

Named Containers

When you have nested containers, you can name them to query specific containers explicitly. This prevents ambiguity about which container a query targets.

Syntax

.sidebar { container-name: sidebar; container-type: inline-size; } .main { container-name: main-content; container-type: inline-size; } /* Query the sidebar container specifically */ @container sidebar (max-width: 300px) { .widget { /* Styles for narrow sidebar */ } } /* Shorthand for name + type */ .sidebar { container: sidebar / inline-size; }

Container Query Units

Container queries introduce new units that are relative to the container's size, similar to how viewport units (vw, vh) relate to the viewport. These enable fluid, proportional sizing based on the container rather than the viewport.

Available Units

/* Container query units */ cqw /* 1% of container's width */ cqh /* 1% of container's height */ cqi /* 1% of container's inline size */ cqb /* 1% of container's block size */ cqmin /* Smaller of cqi or cqb */ cqmax /* Larger of cqi or cqb */

Example

.container { container-type: inline-size; } .responsive-text { /* Font size scales with container width */ font-size: 5cqi; /* 5% of container inline size */ padding: 2cqi; /* Padding scales too */ }

Rendered Result:

Practical Example: Responsive Card

A common use case is a card component that adapts its layout based on available space. The same card can be used in a sidebar (narrow), a grid (medium), or full-width (wide) without any changes to the component code.

CSS

.card-container { container-type: inline-size; } .card { /* Mobile-first: vertical layout */ display: grid; gap: 1rem; } .card img { width: 100%; aspect-ratio: 16/9; } /* Medium containers: horizontal layout */ @container (min-width: 400px) { .card { grid-template-columns: 200px 1fr; } .card img { width: auto; } } /* Large containers: more padding */ @container (min-width: 600px) { .card { padding: 2rem; gap: 2rem; } }

Rendered Result:

Container Queries vs Media Queries

Understanding when to use container queries versus media queries is key to building maintainable, responsive designs.

Aspect Media Queries Container Queries
Based on Viewport size Container size
Best for Page-level layouts Component-level styling
Reusability Page-specific Truly reusable
Example use Sidebar vs. main content Card in sidebar vs. grid
Syntax @media (min-width: 768px) @container (min-width: 400px)

When to Use Each

  • Use Media Queries for page structure (navigation, sidebars, overall layout)
  • Use Container Queries for components (cards, widgets, anything that appears in multiple contexts)
  • Use Both Together for comprehensive responsive design

Practical Example: Grid with Adaptive Items

Container queries shine in grid layouts where each grid item can have different widths depending on the grid configuration. Each item adapts independently based on its own size.

CSS

/* Grid with auto-responsive columns */ .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1rem; } /* Each grid item is a container */ .grid-item { container-type: inline-size; } /* Content adapts to item width */ .grid-item-content { padding: 1rem; } @container (min-width: 300px) { .grid-item-content { padding: 1.5rem; } .grid-item-content h3 { font-size: 1.25rem; } } @container (min-width: 400px) { .grid-item-content { padding: 2rem; } }

Rendered Result:

Style Queries (Experimental)

Beyond size queries, the specification includes style queries (currently limited browser support) that let you query CSS custom properties. This opens up possibilities for theming and state-based styling.

Future Syntax

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

Common Patterns and Best Practices

1. Mobile-First with Container Queries

/* Start with mobile styles */ .component { display: block; } /* Progressive enhancement for larger containers */ @container (min-width: 400px) { .component { display: flex; } }

2. Avoid Circular Dependencies

/* ❌ Bad: Creates circular dependency */ .container { container-type: inline-size; width: 50cqi; /* Width based on its own container! */ } /* ✅ Good: Container size determined externally */ .container { container-type: inline-size; width: 100%; /* Let parent control width */ }

3. Combine with CSS Grid Auto-placement

.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 1rem; } .grid > * { container-type: inline-size; } /* Each item adapts independently */ @container (min-width: 300px) { .card { /* Enhanced styles */ } }

Key Takeaways