Modern Layout with CSS Container Queries
Build components that respond to their container, not the viewport — @container, cqi units and practical patterns.
CSS container queries represent one of the most significant layout capabilities added to the web platform in recent years. Unlike media queries, which respond to viewport dimensions, container queries enable components to adapt based on the size of their parent container. This shift from page-level to component-level responsiveness solves a long-standing problem in design systems: building truly reusable components that look correct in any context without global breakpoint overrides.
Container Queries vs Media Queries
Media queries revolutionized responsive design by allowing styles to change based on viewport width. But viewport width is a poor proxy for the space available to an individual component. A sidebar widget, a dashboard card, and a full-width hero section all exist at different widths even when the viewport is identical.
This mismatch forces developers into awkward workarounds:
- Passing breakpoint props from parent components to override child styles.
- Using JavaScript resize observers to toggle classes based on element width.
- Creating duplicate component variants for different layout contexts.
- Relying on CSS grid and flexbox tricks that break when the layout changes.
Container queries eliminate these workarounds. A component wrapped in a container context automatically adjusts its internal layout when its allocated space changes — whether that is due to viewport resize, sidebar toggle, or grid column reflow.
The @container Rule
Container queries use two CSS constructs: the container-type property on a parent element and the @container at-rule on descendant styles. The parent declares itself as a query container, and children write conditional styles based on the container's dimensions.
/* Parent establishes a query container */
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 1rem;
}
/* Each card container enables size queries for its children */
.product-card {
container-type: inline-size;
container-name: card;
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
overflow: hidden;
}
/* Child styles respond to container width, not viewport */
@container card (min-width: 400px) {
.product-card .card-body {
display: flex;
gap: 1rem;
}
.product-card .card-image {
width: 40%;
flex-shrink: 0;
}
.product-card .card-details {
flex: 1;
}
}
@container card (max-width: 399px) {
.product-card .card-image {
width: 100%;
aspect-ratio: 16 / 9;
}
}
The container-type property accepts inline-size (width in horizontal writing modes), size (both width and height), or normal (no container). Most layout use cases require only inline-size, which is also the most performant option because the browser only tracks one dimension.
Container Query Units
Container queries introduced new CSS length units that reference the query container's dimensions rather than the viewport. These units enable fluid typography and spacing that scales with component size.
- cqw — 1% of the query container's width.
- cqh — 1% of the query container's height.
- cqi — 1% of the query container's inline size.
- cqb — 1% of the query container's block size.
- cqmin — The smaller of cqi and cqb.
- cqmax — The larger of cqi and cqb.
.stat-widget {
container-type: inline-size;
}
.stat-widget .value {
/* Font size scales with container width */
font-size: clamp(1.5rem, 5cqi, 3rem);
}
.stat-widget .label {
font-size: clamp(0.75rem, 2.5cqi, 1rem);
}
Combine container query units with clamp() to create typography that scales smoothly within a component without hard breakpoint jumps. A stat widget in a narrow sidebar column renders smaller text, while the same component in a wide dashboard panel renders larger text — automatically, without props or JavaScript.
Style Queries and Container Query Features
Beyond size queries, the CSS container queries specification includes style queries that respond to computed style values of the container. You can query custom property values, giving components awareness of their parent's theme context.
.theme-container {
container-type: inline-size;
--variant: default;
}
.theme-container[data-variant="compact"] {
--variant: compact;
}
@container style(--variant: compact) {
.nested-component {
padding: 0.5rem;
font-size: 0.875rem;
}
}
Style queries are particularly powerful in design systems where a container sets semantic tokens and child components adapt their density, spacing, and typography accordingly. This pattern replaces prop-drilling variant flags through component trees.
Building Responsive Components Without Media Queries
The practical goal of container queries is components that work correctly everywhere they are placed. Consider a data table component used in a full-page view, a modal dialog, and a dashboard widget. With media queries alone, all three instances share the same breakpoint logic tied to viewport width, producing broken layouts in at least one context.
With container queries, the table component defines its own responsive behavior:
- Above 600px container width — Show all columns in a standard table layout.
- 400px to 600px — Hide low-priority columns, reduce padding.
- Below 400px — Switch to a stacked card layout with label-value pairs.
.data-table-wrapper {
container-type: inline-size;
container-name: table;
overflow-x: auto;
}
@container table (max-width: 399px) {
.data-table thead {
display: none;
}
.data-table tr {
display: block;
margin-bottom: 1rem;
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
padding: 0.75rem;
}
.data-table td {
display: flex;
justify-content: space-between;
padding: 0.25rem 0;
}
.data-table td::before {
content: attr(data-label);
font-weight: 600;
}
}
This component requires zero knowledge of its parent's layout. Drop it into any container and it adapts. That is the promise of container queries fulfilled.
Framework Integration
Modern CSS frameworks embrace container queries natively. Tailwind CSS v4 includes container query variants — prefix utilities with @ followed by the breakpoint to apply styles based on container size. Styled-components and other CSS-in-JS libraries support the @container at-rule in template literals without additional configuration.
In React component libraries, establish container context at the component root and let internal elements use container queries for layout decisions. Document which components are container-aware so consumers know to avoid constraining them below their minimum functional width.
Browser Support and Progressive Enhancement
Container queries enjoy broad browser support as of 2026, with coverage across Chrome, Firefox, Safari, and Edge. For the small percentage of legacy browsers without support, apply progressive enhancement: design the default styles for the most common container size, then add container query overrides for supported browsers.
Use the @supports rule to detect container query support and provide media query fallbacks where necessary:
/* Fallback for browsers without container query support */
@media (max-width: 600px) {
.product-card .card-body {
flex-direction: column;
}
}
/* Enhanced layout for supporting browsers */
@supports (container-type: inline-size) {
@container card (max-width: 399px) {
.product-card .card-body {
flex-direction: column;
}
}
}
Container queries mark a maturation of CSS as a language for component-driven design. By shifting responsive logic from the page level to the component level, they enable design systems where every component is truly self-contained, adaptive, and reusable. Embrace container queries in your next project and experience responsive design the way it was always meant to work.