Container queries
A media query looks at the width of the window. But the same card can stand both in a wide column and in a narrow sidebar — while there is only one window. Container queries check the width of a parent block, and the card decides by itself how to look. They work in all modern browsers since 2023.
The container
First the parent is declared a container — a block whose size can be checked. The container-type: inline-size property does that. Inline size is the size along a line of text, that is, the width for normal text:
.wrapper {
container-type: inline-size;
}On its own a container changes nothing visually. It only lets its descendants ask about its width.
The @container rule
The @container rule is like @media, but its condition checks the width of the nearest container. Below, the same card stands in two containers of different widths:
<style>
.wrapper { container-type: inline-size; margin-bottom: 8px; border: 1px dashed gray; }
.narrow { width: 220px; }
.wide { width: 440px; }
.card { display: grid; gap: 8px; padding: 8px; background: lavender; }
.pic { height: 60px; background: mediumpurple; }
@container (min-width: 300px) {
.card { grid-template-columns: 100px 1fr; }
}
</style>
<div class="wrapper narrow">
<div class="card"><div class="pic"></div><p>The picture above the text</p></div>
</div>
<div class="wrapper wide">
<div class="card"><div class="pic"></div><p>The picture to the left of the text</p></div>
</div>The card code is the same, but the look differs: in the narrow container the condition is false, in the wide one it is true.
Drag the corner
To watch the switch live, the container can be allowed to change its width with the mouse — the resize: horizontal property. Drag the bottom right corner of the frame:
<style>
.wrapper { container-type: inline-size; resize: horizontal; overflow: hidden; width: 240px; max-width: 100%; border: 1px dashed gray; }
.card { padding: 12px; background: honeydew; }
@container (min-width: 360px) {
.card { background: gold; font-size: 20px; }
}
</style>
<div class="wrapper">
<div class="card">Stretch the frame wider than 360 pixels</div>
</div>The browser window does not change, but the card rebuilds itself.
Container names
If containers are nested, @container looks at the nearest one. To refer to a particular one, give it a name with container-name. The container shorthand sets the name and the type at once:
.sidebar {
container: sidebar / inline-size;
}
@container sidebar (max-width: 250px) {
.menu { font-size: 14px; }
}Container units
Special units work inside a container. cqi is one percent of the container width, like vw for the window:
<style>
.wrapper { container-type: inline-size; width: 60%; border: 1px dashed gray; }
.title { font-size: 10cqi; margin: 0; }
</style>
<div class="wrapper">
<p class="title">10cqi</p>
</div>The font is a tenth of the frame width and grows together with it.
Common mistake
An element cannot check its own width: an @container condition looks at an ancestor. If the card itself is declared a container, its styles inside the query do not apply:
<style>
.card { container-type: inline-size; padding: 12px; background: mistyrose; }
@container (min-width: 100px) {
.card { background: gold; }
}
</style>
<div class="card">I am a container, but I cannot change myself</div>The card stayed pink. Declare the wrapper a container, and write the query styles for what is inside it.