Container Queries Deep Dive
Beyond Media Queries
Media queries respond to viewport size. Container queries respond to a parent container’s size — enabling truly reusable components that adapt to their context, not the screen.
A card in a narrow sidebar and a wide main column can use the same component with different layouts.
Enabling Container Queries
A parent must be a query container:
.card-wrapper {
container-type: inline-size;
container-name: card;
}
| Property | Values | Effect |
|---|---|---|
container-type |
normal, size, inline-size |
Which dimensions to query |
container-name |
custom name | Named container for @container |
container |
shorthand | type + name combined |
Use inline-size for most component layouts (width in horizontal writing mode).
Basic Container Query
.card-container {
container-type: inline-size;
}
@container (min-width: 400px) {
.card {
display: flex;
flex-direction: row;
gap: 1rem;
}
.card__image {
width: 40%;
}
}
@container (max-width: 399px) {
.card {
display: block;
}
.card__image {
width: 100%;
}
}
<div class="card-container">
<article class="card">...</article>
</div>
Named Containers
When nesting containers, name them to target specific ancestors:
.sidebar {
container-type: inline-size;
container-name: sidebar;
}
.main {
container-type: inline-size;
container-name: main;
}
@container sidebar (max-width: 250px) {
.widget { font-size: 0.875rem; }
}
@container main (min-width: 600px) {
.widget { display: grid; grid-template-columns: 1fr 1fr; }
}
Shorthand container
.card-wrapper {
container: card / inline-size;
/* equivalent to:
container-name: card;
container-type: inline-size;
*/
}
@container card (min-width: 500px) { ... }
Container Query Units
Size-relative units based on container dimensions:
| Unit | Reference |
|---|---|
cqw |
1% of container width |
cqh |
1% of container height |
cqi |
1% of inline size |
cqb |
1% of block size |
cqmin |
smaller of cqi/cqb |
cqmax |
larger of cqi/cqb |
@container (min-width: 300px) {
.card__title {
font-size: clamp(1rem, 4cqi, 1.5rem);
}
}
Typography scales with container, not viewport — ideal for design systems.
Style Queries (Emerging)
Query computed styles of container (limited browser support — check caniuse):
@container style(--theme: dark) {
.card { background: #1a1a2e; }
}
Container Query vs Media Query
| Scenario | Use |
|---|---|
| Page-level breakpoints | Media query |
| Reusable component adapts to slot width | Container query |
| Sidebar vs main column same component | Container query |
| Mobile navigation toggle | Media query |
Practical Patterns
Responsive Card Grid Item
.product-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 1rem;
}
.product-cell {
container-type: inline-size;
}
@container (min-width: 280px) {
.product {
flex-direction: row;
}
.product__details { padding-left: 1rem; }
}
Hide Labels in Narrow Containers
@container (max-width: 200px) {
.stat-label { display: none; }
.stat-value { font-size: 1.25rem; }
}
Container-Aware Navigation
.nav-container {
container-type: inline-size;
}
@container (max-width: 400px) {
.nav { flex-direction: column; }
.nav__links { display: none; }
.nav__menu-btn { display: block; }
}
Fallback for Unsupported Browsers
.card { display: block; }
@supports (container-type: inline-size) {
.card-wrapper { container-type: inline-size; }
@container (min-width: 400px) {
.card { display: flex; }
}
}
Container queries supported in all modern browsers (Chrome 105+, Safari 16+, Firefox 110+).
Performance Considerations
- Container queries create size containment — layout calculations scoped to container
- Avoid deep nesting of query containers
- Don’t set
container-type: sizeunless you need both dimensions — requires explicit height
Best Practices
- Set container on wrapper, not the component itself
- Use
inline-sizeunless height-based queries needed - Name containers in complex nested layouts
- Combine with media queries — page structure vs component behavior
- Test component in multiple contexts — sidebar, modal, full width
Troubleshooting
Container query not applying
- Verify ancestor has
container-typeset - Component must be descendant of container, not the container itself
Query never matches
- Check container has defined width (not
width: autocollapsing to zero) - Use DevTools → Elements → container badge (Chrome)
Unexpected layout with size containment
container-type: sizerequires explicit height on container
Container queries complete the responsive design story — build components that adapt to their environment, not just the viewport.