Responsive Components with CSS Container Queries

Responsive components without media queries

Media queries respond to the viewport. Components live in containers: sidebars, modals, grids. @container lets them respond to their actual available space.

Old way Viewport-based
.card   {  display: grid;  grid-template-columns: 1fr;}@media (min-width: 768px)   {  .card   {    grid-template-columns: auto 1fr;  }}
Container-based
.wrapper   {  container-type: inline-size;}.card   {  grid-template-columns: 1fr;}@container (width > 400px)   {  .card   {    grid-template-columns: auto 1fr;  }}
Widely available Since 2023 93% global usage

This feature is well established and works across many devices and browser versions. It has been available across browsers since 2023.

Safe to use without fallbacks.

105+
110+
16+
105+
drag the handle to resize the container
Card title
This component adapts to its container width. Resize the wrapper to see it change.

Component-level responsive

Components adapt to their own container. Same card works in a sidebar, modal, or full-width grid.

Truly reusable

No more breakpoint math for every context. The component carries its responsive logic with it.

Precise control

Query the nearest container, not the whole viewport. Each section of the page can behave independently.

Key Change
Scope
Viewport → Container
Old Approach
@media
Viewport-dependent
Modern Approach
@container
Context-aware

How it works

First, mark a parent as a container with container-type: inline-size. This tells the browser to track its width for query purposes.

Then use @container (width > 400px) instead of @media. The query now fires based on the container's width, not the viewport. Your card can be 300px wide in a sidebar and 800px wide in a main area, and it'll adapt correctly in both. For fluid typography, container queries pair well with cqi units.

You can even name containers with container-name to target specific ancestors when nesting multiple containers.

ESC