CSS Container Queries
CSS container queries allow styles to respond to the characteristics of a containing element instead of only responding to the viewport. This makes it possible to create reusable components that adapt according to the space available where they are placed.
A card, navigation component, product panel, or other reusable element can change its layout based on the size of its container, allowing the same component to work in different areas of a responsive page.
How Container Queries Work
A media query commonly responds to the viewport. A container size query instead evaluates the dimensions of an ancestor that has been established as a query container.
This is useful when the same component can appear in different parts of a page. A card placed in a narrow sidebar can use one layout while the same card placed in a wider content area can use another.
.card-container {
container-type: inline-size;
}
@container (min-width: 500px) {
.card {
display: grid;
grid-template-columns: 1fr 2fr;
}
}
The card changes to a two-column layout when its query container reaches the specified width.
Creating a Query Container
Before using a size container query, an ancestor element must be established as an appropriate query container.
.card-container {
container-type: inline-size;
}
The container-type property determines which dimensions can be queried.
Descendants of the container can then use an @container rule that responds to the container's size.
@container (min-width: 500px) {
.card {
display: flex;
}
}
container-type
The container-type property establishes an element as a query container for size-related container queries.
| Value | Description |
|---|---|
normal |
The element is not a query container for size queries. |
inline-size |
Allows queries based on the container's inline dimension. |
size |
Allows queries based on both the inline and block dimensions. |
For many responsive components, inline-size is the appropriate choice because the component primarily needs to respond to the available horizontal space.
.component-container {
container-type: inline-size;
}
@container Rule
The @container at-rule contains CSS that is applied when its container query condition matches.
@container (min-width: 400px) {
.card {
padding: 2rem;
}
}
The additional padding is applied when the relevant query container is at least 400 pixels wide.
Like media queries, container queries can change multiple declarations or alter an entire component layout when the condition matches.
Named Containers
The container-name property gives a query container a name. A named container can be targeted by an @container rule.
.sidebar {
container-type: inline-size;
container-name: sidebar;
}
@container sidebar (min-width: 400px) {
.card {
display: grid;
grid-template-columns: 1fr 2fr;
}
}
Using a container name can make it clear which ancestor a query is intended to use, especially when components are nested inside several possible query containers.
container Shorthand
The container shorthand can set the container name and type in one declaration.
.sidebar {
container: sidebar / inline-size;
}
The name appears before the slash and the container type appears after it.
This is equivalent to:
.sidebar {
container-name: sidebar;
container-type: inline-size;
}
Container Query Ranges
Container size queries can use minimum and maximum conditions in a form similar to traditional media queries.
@container (min-width: 400px) {
.card {
display: flex;
}
}
Modern range syntax can also use comparison operators.
@container (width >= 400px) {
.card {
display: flex;
}
}
A query can also describe a bounded range.
@container (400px <= width <= 700px) {
.card {
padding: 2rem;
}
}
The rule applies when the query container's width falls within the specified range, including both boundaries.
Container Query Units
CSS provides relative length units based on the dimensions of a query container.
| Unit | Relative To |
|---|---|
cqw |
One percent of the query container's width. |
cqh |
One percent of the query container's height. |
cqi |
One percent of the query container's inline size. |
cqb |
One percent of the query container's block size. |
cqmin |
The smaller of the cqi and cqb values. |
cqmax |
The larger of the cqi and cqb values. |
.card h2 {
font-size: clamp(1.5rem, 6cqi, 3rem);
}
This allows the heading size to respond to the inline size of its query container while the clamp() function limits how small or large the text can become.
Container Queries vs Media Queries
Media queries and container queries solve related but different responsive design problems.
| Feature | Responds To | Common Use |
|---|---|---|
| Media Query | Viewport, device, or user-related media features | Page-level responsive design |
| Container Query | A qualifying ancestor container | Component-level responsive design |
A media query is useful when the overall page should change according to the viewport.
@media (min-width: 900px) {
.page {
grid-template-columns: 2fr 1fr;
}
}
A container query is useful when a component should respond to the space provided by its own layout context.
@container (min-width: 500px) {
.card {
grid-template-columns: 1fr 2fr;
}
}
The two techniques can be used together in the same responsive design.
When to Use Container Queries
Container queries are especially useful for reusable components that may appear in different locations or at different widths.
| Situation | Possible Use |
|---|---|
| Card component | Switch between stacked and side-by-side content. |
| Sidebar component | Adjust controls according to the sidebar width. |
| Reusable navigation | Change the arrangement when its container provides more space. |
| Dashboard widget | Adapt information density to the widget's available area. |
If a responsive change depends on the overall viewport, a media query may be more appropriate. If it depends on the space allocated to a particular component, a container query can make that component more independent and reusable.
CSS Container Query Example
The following example establishes each wrapper as an inline-size query container. The card changes from a stacked layout to two columns when its own container reaches 500 pixels.
.card-container {
container-type: inline-size;
}
.card {
display: grid;
grid-template-columns: 1fr;
}
@container (min-width: 500px) {
.card {
grid-template-columns: 1fr 2fr;
}
}
This allows copies of the same card component to use different layouts on the same page when their containers have different widths.
Open the example in the editor and change the 500px query value. Drag the divider between the code and result panes to change the preview width and see how each component responds to the width of its container.
