Media queries have always felt wrong — why does a sidebar card care about the browser window width? Container queries solve this elegantly and they're now supported everywhere.
For years, we hacked around a fundamental limitation: media queries respond to the viewport, not the container an element lives in. A card component inside a narrow sidebar behaved identically to the same card in a full-width grid, even though the available space was completely different.
The Problem with Media Queries
Imagine a <BlogCard> component. In a sidebar it gets 280px. In a grid it gets 400px. In a hero it gets 800px. With media queries, you'd need to know the context of each usage and write specific overrides. With container queries, the card simply responds to how much space it actually has.
/* Step 1: declare which element is the container */
/* inline-size: responds to width only (most common) */
.card-wrapper {
container-type: inline-size;
container-name: card; /* name it so nested @container can target it */
}
.card {
display: flex;
flex-direction: column; /* default: stacked layout for narrow containers */
gap: 1rem;
}
/* Step 2: query the container's size, not the viewport */
/* This fires when .card-wrapper is >= 400px, regardless of screen width */
@container card (min-width: 400px) {
.card {
flex-direction: row; /* side-by-side when there's room */
align-items: center;
}
.card-image {
width: 160px;
flex-shrink: 0; /* image stays 160px even in flex layout */
}
}
Container Query Units
Container queries also introduced new length units: cqw (1% of container width), cqh, cqi (inline), cqb (block), cqmin, and cqmax. These let you size elements relative to their container rather than the viewport — a typography dream.
.card-title {
/* Font scales with the card width, not the screen */
/* clamp: min 1rem, scales at 4% of container width, caps at 2rem */
/* In a narrow container: stays at 1rem. Wide container: grows proportionally */
font-size: clamp(1rem, 4cqw, 2rem);
}
Browser Support
As of early 2024, container queries have 92%+ global browser support (Chrome 105+, Firefox 110+, Safari 16+). There's no longer any reason to avoid them in production. The polyfill is also solid for the remaining edge cases.
See container queries in action — resize the container and watch the card layout respond
Start by finding one component in your codebase that has different layouts depending on where it's placed — a card, a header, a media block. Add container-type: inline-size to its wrapper and replace the media query overrides with @container rules. Once you see how much simpler the component becomes, you won't go back.
Top comments (0)