CSS Container Queries: The Future of Responsive Design (2026)
For years developers wishlisted "responsive based on parent container, not viewport". In 2026, finally: container queries stable across all major browsers. But many developers still default to media query for everything, when container query is better suited for many situations.
This article covers container queries from basic to advanced patterns, plus when to use which between container query vs media query.
The Problem Container Queries Solve
For a long time, responsive design used media queries based on viewport size. Problem: reusable components used in multiple locations have different sizes despite same viewport.
Example: card component used in:
- Sidebar (300px wide)
- Main content (700px wide)
- Modal (500px wide)
Media query doesn't help because viewport same for all three cases. Solution before container queries: use props or JavaScript to handle, not clean.
Container query: card adapts based on parent's size, not viewport. Different layouts for each context, from pure CSS.
Basic Syntax
Setup container:
.parent {
container-type: inline-size;
/* or "size" for both width + height */
container-name: card-container; /* optional, for multiple containers */
}
Style based on container size:
@container (min-width: 400px) {
.card {
display: grid;
grid-template-columns: auto 1fr;
gap: 1rem;
}
}
@container (min-width: 700px) {
.card {
grid-template-columns: 200px 1fr 200px;
}
}
/* With named container */
@container card-container (min-width: 400px) {
.card { padding: 2rem; }
}
Same card, in different parents, renders different layouts. Without JavaScript.
Practical Patterns
1. Adaptive Card Component
<div class="card-wrap">
<article class="card">
<img src="..." alt="...">
<div class="content">
<h3>Title</h3>
<p>Description...</p>
</div>
</article>
</div>
.card-wrap {
container-type: inline-size;
}
.card {
display: grid;
}
/* Compact: stacked vertically */
.card .content { padding: 1rem; }
/* Wide: horizontal layout */
@container (min-width: 400px) {
.card {
grid-template-columns: 200px 1fr;
}
}
@container (min-width: 700px) {
.card {
grid-template-columns: 300px 1fr;
}
.card .content { padding: 2rem; font-size: 1.1rem; }
}
2. Sidebar Widget
Adaptive widget: if sidebar persistent, vertical layout. If sidebar collapses to top bar, horizontal layout.
aside {
container-type: inline-size;
}
.widget {
display: flex;
flex-direction: column;
}
@container (min-width: 600px) {
.widget {
flex-direction: row;
justify-content: space-between;
}
}
3. Form Field Layout
Form auto-adjusting label position based on available width:
.form {
container-type: inline-size;
}
.field {
display: grid;
gap: 0.5rem;
}
@container (min-width: 500px) {
.field {
grid-template-columns: 200px 1fr;
align-items: center;
}
}
Form in narrow modal: label on top. Form on wide page: label on side.
4. Navigation Menu
nav {
container-type: inline-size;
}
.menu {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
@container (min-width: 600px) {
.menu {
flex-direction: row;
gap: 2rem;
}
}
@container (max-width: 599px) {
.menu-toggle {
display: block; /* Show hamburger */
}
.menu {
display: none;
}
.menu.open {
display: flex;
}
}
Container Query Units
Besides container queries, container queries also bring new units:
cqw: 1% container widthcqh: 1% container heightcqi: 1% container inline sizecqb: 1% container block sizecqmin: min of cqi/cqbcqmax: max of cqi/cqb
Use case: text scaling based on container, not viewport:
.parent {
container-type: inline-size;
}
.title {
font-size: clamp(1.5rem, 5cqw, 3rem);
/* Scale based on container width, with min/max */
}
Title is 5% of container width, with minimum 1.5rem and maximum 3rem.
Container Query vs Media Query: When to Use Which
Use Media Query For:
- Page-level layout: full page restructure based on device size
- Print stylesheet:
@media print - Reduced motion:
@media (prefers-reduced-motion: reduce) - Color scheme:
@media (prefers-color-scheme: dark) - Hover capability:
@media (hover: hover) - Device pixel ratio: for retina image swap
Use Container Query For:
- Reusable components: cards, widgets, forms, navigation
- Multi-context components: used in sidebar and main content
- Library / design system components: distribute components adapting without consumer config
- Component-level layouts: internal headers, adaptive footers
Performance Considerations
1. Browser Cost
Container queries trigger layout recalculation when container size changes. For most cases, minimal cost. But excessive container queries in deeply nested levels can impact performance.
Best practice: limit container hierarchy to 2-3 levels. Each component needing container is usually only 1 level.
2. Layout Containment
container-type: inline-size implicitly applies contain: layout style inline-size. Element becomes containing block. There are side effects:
- Position: absolute on children will position relative to container, not other ancestors
- Elements can't "leak" out of container for layout
Most cases this is desirable, but if your component relies on positioning to other ancestors, test carefully.
Browser Support 2026
- Chrome / Edge: full support since v105 (2022)
- Safari: full support since 16.0 (2022)
- Firefox: full support since 110 (2023)
- Mobile: all modern mobile browsers support
Coverage 95%+ in 2026. For older browsers, fallback to media queries or JavaScript.
Common Pitfalls
1. Forgetting to Set container-type
Most common mistake. You write @container rule but forget to set parent as container. Rule doesn't apply.
/* Wrong - parent isn't container */
@container (min-width: 400px) {
.card { ... }
}
/* Right */
.parent {
container-type: inline-size; /* REQUIRED */
}
@container (min-width: 400px) {
.card { ... }
}
2. Applying to Self Element
Container queries can't style elements that are themselves containers. The element becomes container, you style its descendants.
/* Wrong - .self is container, applied to itself */
.self {
container-type: inline-size;
}
@container (min-width: 400px) {
.self { padding: 2rem; } /* DOESN'T WORK */
}
/* Right - container styling outside @container, descendants inside */
.self {
container-type: inline-size;
padding: 1rem;
}
@container (min-width: 400px) {
.self > .child { padding: 2rem; } /* WORKS */
}
3. Width 0 Issue
Elements with display: contents or no meaningful width, container doesn't work as expected. Container needs resolvable width.
4. Naming Collision
Multiple ancestors becoming containers, query can match ancestor you don't expect. Use container-name for specificity.
Closing
Container queries finally solve a long-standing problem in responsive design: components adapting to context, not viewport. Browser support now stable, syntax mature, performance acceptable.
In 2026, if you build component-based design systems, container queries should be default tool. Use media queries for page-level layouts, container queries for component-level adaptation.
What you don't need: rewrite all existing stylesheets to use container queries. Apply gradually for new components or components where current pattern is awkward with media queries.
Plus: explore container query units (cqw, cqh, etc.). They unlock fluid typography and spacing patterns previously needing JavaScript ResizeObserver.