Container Queries & Style Queries
Shift responsive logic from the viewport to the component itself — container and style queries finally let CSS respond to where a component lives, not just how wide the screen is.
6 min read
The full lesson
For decades, making a component respond to its environment meant tying it to the viewport with media queries — a global ruler applied to a local problem. A card that looks great at 400 px wide inside a sidebar breaks at that same viewport width when placed in a full-bleed layout. Container queries and style queries fix this. They let a component adapt to the space it actually occupies and to values already set on its ancestors. They are the biggest advance in responsive CSS since media queries were introduced.
Why Viewport-Only Media Queries Fall Short
A traditional responsive layout measures the browser window and switches layouts at fixed breakpoints. This works when components are full-width. But modern interfaces are more complex: dashboards with resizable panels, design systems that must render a card in a 200 px sidebar and a 600 px article grid at the same time, drag-and-drop builders where users can place widgets anywhere.
The symptom is a pile of ever-more-specific media queries that are really just asking “how wide is the container?” Teams end up with breakpoint hacks — overriding a globally-triggered layout with container-specific exceptions — because the underlying model is wrong. The right model is component-scoped responsiveness.
Container Queries: The Basics
To make a parent element a containment context, set container-type on it. The browser then exposes that element’s dimensions to any descendant’s @container rule.
/* 1. Establish a containment context */
.card-wrapper {
container-type: inline-size;
container-name: card;
}
/* 2. Query that context from inside the component */
@container card (min-width: 480px) {
.card {
display: grid;
grid-template-columns: 200px 1fr;
}
}
@container card (width < 480px) {
.card {
display: flex;
flex-direction: column;
}
}
Key details:
container-type: inline-sizeis the most common setting. It tracks the container’s inline (horizontal) dimension without requiring you to know the element’s height ahead of time.container-type: sizeenables queries on both axes but requires the element to have a fixed block size. Use it only for components like modals or fixed panels.- Naming containers with
container-nameis optional, but recommended when you have nested containers. An unnamed@containerquery resolves against the nearest ancestor containment context, which can be surprising. - You can combine both into one shorthand:
container: card / inline-size.
Browser Support in 2026
Container queries shipped in all major engines — Chromium, Firefox, and Safari — by late 2023. They now have near-universal support. You can use them without a polyfill for any project that drops IE. The container-queries feature guard you may have seen in older tutorials is no longer needed.
Container Query Units
Once a containment context exists, you get a set of context-relative units. You can use them inside @container rules and even in regular property values when the element is inside a containing ancestor.
| Unit | Meaning |
|---|---|
cqi | 1% of the container’s inline size |
cqb | 1% of the container’s block size |
cqw | 1% of the container’s width |
cqh | 1% of the container’s height |
cqmin | 1% of the smaller of cqw/cqh |
cqmax | 1% of the larger of cqw/cqh |
These units let you build fluid typography and spacing that scale with the container, not the viewport. Think of them as the container-scoped version of vw.
.card__title {
font-size: clamp(1rem, 3cqi + 0.5rem, 1.75rem);
}
This is a big improvement over viewport-unit fluid type when a component can appear in many different layout positions.
Style Queries
Style queries extend the @container syntax to test computed CSS custom property values on a container — not just its dimensions. They answer a different question: “does my ancestor declare a certain design state?”
/* Mark a surface as 'promotional' using a custom property */
.promo-banner {
--surface-variant: promotional;
}
/* Children query the computed value */
@container style(--surface-variant: promotional) {
.cta-button {
background: oklch(65% 0.2 30);
font-weight: 700;
}
}
Style queries currently only work with custom properties (CSS variables). Querying standard properties like color or display is in the specification but not yet implemented across all engines as of mid-2026. Check the @container style() support tables before using standard-property style queries in production.
Where Style Queries Shine
Style queries cleanly solve several patterns that previously required JavaScript or extra wrapper elements.
Theme propagation without class drilling. Instead of adding class="dark-surface" to every child that needs to change appearance, set a custom property on the ancestor and let descendants query it.
.surface--elevated {
--elevation: 2;
}
@container style(--elevation: 2) {
.icon {
filter: drop-shadow(0 2px 4px oklch(0% 0 0 / 30%));
}
}
Variant-aware sub-components. A design system card can expose --card-variant: compact | default | featured. Every sub-component (title, image, actions) can query that value and adapt on its own — the parent never needs to pass explicit props to each child.
Practical Patterns
Component-Level Breakpoints for Design System Components
This is the killer use case. A card component in your design system should be fully self-contained: give it a containing parent and it figures out its own layout.
.card {
container: card / inline-size;
display: flex;
flex-direction: column;
gap: 1rem;
padding: 1rem;
}
@container card (min-width: 360px) {
.card__body {
display: grid;
grid-template-columns: 1fr 2fr;
gap: 1.25rem;
}
}
@container card (min-width: 600px) {
.card {
padding: 1.5rem 2rem;
}
.card__title {
font-size: clamp(1.25rem, 2.5cqi, 2rem);
}
}
The same component renders as a stacked mobile card in a narrow sidebar and as a horizontal feature card in a wide main area — zero JavaScript, zero page-level breakpoint overrides.
Nesting Containers
Containers can nest. An @container rule always queries the nearest named ancestor, or the nearest unnamed containment context if no name is given. This lets you build layouts where a sidebar has its own containment context, completely independent of a main panel.
.layout {
container: layout / inline-size;
}
.sidebar {
container: sidebar / inline-size;
}
/* Queries the sidebar, not the layout */
@container sidebar (max-width: 200px) {
.nav-label {
display: none;
}
}
Always name your containers in non-trivial layouts. Unnamed queries against the nearest context are hard to reason about when containers nest.
Combining Container Queries with Media Queries
Container queries do not replace media queries. They complement them.
Use media queries for:
- Global layout shifts (switching from a one-column to a multi-column page shell)
- User preference features (
prefers-color-scheme,prefers-reduced-motion,prefers-contrast) - Print stylesheets
Use container queries for:
- Component-level layout changes
- Typography scaling within a component
- Showing or hiding sub-elements based on available space
Do
Set container-type: inline-size on layout wrappers and let components query their own available space. Use @media for page-shell transitions and user preference features. Name every containment context in complex layouts.
Don't
Keep writing media queries that are really proxies for container width. Apply container-type: size unless you have a fixed-height container — it requires explicit block sizing and breaks height-driven content. Leave containers unnamed when you have nested containment.
Style Queries for Theming
The most immediately practical style query pattern is surface-aware theming. Components adapt their appearance based on the surface they sit on, without any prop-drilling of theme flags.
:root {
--surface-tone: neutral;
}
.surface--brand {
--surface-tone: brand;
background: oklch(40% 0.18 260);
color: oklch(97% 0.01 260);
}
.surface--danger {
--surface-tone: danger;
background: oklch(40% 0.18 25);
color: oklch(97% 0.01 25);
}
/* Button adapts to its surface without needing extra props */
@container style(--surface-tone: brand) {
.btn--secondary {
border-color: oklch(80% 0.1 260);
color: oklch(90% 0.05 260);
}
}
@container style(--surface-tone: danger) {
.btn--secondary {
border-color: oklch(80% 0.1 25);
color: oklch(90% 0.05 25);
}
}
This technique pairs well with OKLCH-based design token palettes. The lightness and chroma values stay consistent while only the hue shifts, which keeps perceived contrast ratios predictable across surface variants.
Accessibility Considerations
Container queries are a layout mechanism. They have no direct WCAG 2.2 implications on their own, but they interact with accessibility in two important ways.
Zoom and text resize. If your container-relative typography uses cqi units, test at 200% browser zoom. Unlike vw units (which scale with the viewport), cqi units scale with the container. If a container is a percentage of the viewport width, the computed cqi value grows with zoom — that is generally correct behavior. Still, make sure your clamp() floors use rem so minimum sizes respect the user’s base font preference.
Reflow at 320 px. WCAG 2.2 Success Criterion 1.4.10 (Reflow) requires content to be readable at a 320 CSS pixel viewport width without horizontal scrolling. Container queries make this easier to achieve because each component independently collapses to a single-column layout when its container is narrow — but you still need to test it.
What to Stop Doing
Outdated responsive practice tied every layout decision to device-specific pixel breakpoints — 375 px for “mobile”, 768 px for “tablet”, 1024 px for “desktop”. This model:
- Breaks the moment a component lands in an unexpected context (a modal, a sidebar, a resizable panel)
- Creates hundreds of highly specific media query overrides as design systems grow
- Ties the component library to page-level concerns it has no business knowing about
Container queries replace the majority of component-level media queries. Viewport media queries should govern only true page-level structures: the document shell, navigation, footer layout, and user-preference adaptations.