Advanced container query patterns. The intermediate tutorial covered container-type, @container, and named containers. Here we combine size and style queries, chain conditions, handle fallbacks, and design components that adapt to their slot without viewport media queries.
Query lists and compound conditions
Multiple conditions in one @container rule use implicit AND logic:
.article-slot {
container: article / inline-size;
--layout: stack;
}
@container article (min-width: 36rem) and (min-height: 20rem) {
.article-preview {
display: grid;
grid-template-columns: 180px 1fr;
gap: 1.25rem;
}
}
Both width and height must pass. Useful when a tall narrow slot needs a different treatment from a wide shallow one.
Size plus style queries
Style queries match custom property values on the container. Combine them with size for layout that responds to both slot width and a theme flag:
.promo-slot {
container: promo / inline-size;
--density: comfortable;
}
.promo-slot[data-density="compact"] {
--density: compact;
}
@container promo (min-width: 24rem) {
.promo {
padding: 1.5rem;
}
}
@container promo style(--density: compact) {
.promo {
padding: 0.75rem;
font-size: 0.875rem;
}
}
The parent sets --density; children react without extra modifier classes on every descendant. Style query support is still expanding – test in target browsers and keep a class-based fallback for critical layouts.
Container query length units in practice
cqi, cqw, and friends scale with the container, not the viewport. Use them inside components whose padding and type should grow with the slot:
.metric-slot {
container-type: inline-size;
}
.metric {
padding: clamp(0.75rem, 3cqi, 1.5rem);
}
.metric__value {
font-size: clamp(1.25rem, 5cqi + 0.5rem, 2.75rem);
font-variant-numeric: tabular-nums;
}
Pair clamp() with container units so values do not explode in very wide slots. A max cap matters.
Nested containers and query targets
When containers nest, unnamed queries target the nearest ancestor. Named queries skip intermediate containers:
.dashboard {
container: dashboard / inline-size;
}
.widget-frame {
container: widget / inline-size;
}
@container dashboard (min-width: 64rem) {
.widget-frame {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
}
@container widget (max-width: 18rem) {
.widget__chart {
display: none;
}
.widget__summary {
font-size: 0.875rem;
}
}
Dashboard-level rules reshape the grid; widget-level rules simplify content inside a cramped cell. Two concerns, two named containers.
Fallbacks without @supports hacks everywhere
Default styles should work without container queries. Treat @container rules as enhancements:
/* baseline: stacked layout everywhere */
.product-card {
display: flex;
flex-direction: column;
gap: 0.75rem;
}
@container (min-width: 28rem) {
.product-card {
flex-direction: row;
align-items: center;
}
}
Without containment, the baseline stack still renders. With containment, the horizontal layout kicks in. No duplicate HTML variants.
Container queries vs media queries – a decision table
- Page shell – media queries (nav collapse, sidebar visibility).
- Reusable card, table, chart – container queries.
- Global type scale – root
clamp()or media queries. - Component padding in a grid cell – container units.
The next tutorial covers view transitions – animating between DOM states and page navigations without bolting on a full SPA framework.

