Layout Intermediate

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 Viewport-based
1.card {
2  display: grid;
3  grid-template-columns: 1fr;
4}
5
6@media (min-width: 768px) {
7  .card {
8    grid-template-columns: auto 1fr;
9  }
10}
11/* Breaks when .card is in a sidebar */
Modern
Container-based
1.wrapper {
2  container-type: inline-size;
3}
4
5.card { grid-template-columns: 1fr; }
6
7@container (width > 400px) {
8  .card {
9    grid-template-columns: auto 1fr;
10  }
11}
12/* Adapts to its container, not viewport */
container: 100%
Card title
This component adapts to its container width, not the viewport. 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.

Browser Support
90%
Chrome Firefox Safari Edge
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.

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

ESC