We’re still in suuuuuper early days with container queries. Too early for broad browser support, but Chromium already supports it, Safari started supporting it in version 16, and Firefox is presumably not far behind.
Most early days conversations revolving around container queries usually compare the syntax to media queries.
/* Stacked flex container */
.post {
display: flex;
flex-direction: column;
}
/* Change direction when viewport is 600px or wider */
@media(min-width: 600px) {
.post {
flex-direction: row;
}
}
/* Define the container */
.posts {
container-name: posts;
container-type: inline-size;
}
.post {
display: flex;
flex-direction: column;
}
/* Query the container's min-width */
@container posts (min-width: 600px) {
/* Change styles when `posts` container is 600px or wider */
.post {
flex-direction: row;
}
}
Both of these are making queries for min-width: 600
. The difference is that the media query is looking at the viewport’s width to trigger those style changes while the container query is looking at the computed width of the .posts
element. Sweet!
But after listening to CSS Podcast Episode 59, Una and Adam poked at the future of container queries: style queries! The current working draft of the CSS Containment Module Level 3 spec defines container style queries:
A container style query allows querying the computed values of the query container. It is a boolean combination of individual style features (<style-feature>) that each query a single, specific property of the query container.
But no examples on syntax just yet — only a brief description:
The syntax of a <style-feature> is the same as for a declaration, and its query is true if the computed value of the given property on the query container matches the given value (which is also computed with respect to the query container), unknown if the property or its value is invalid or unsupported, and false otherwise. The boolean syntax and logic combining style features into a style query is the same as for CSS feature queries. (See @supports.)
So, yes, given time we should expect to pull off something like this:
.posts {
container-name: posts;
}
@container posts (background-color: #f8a100) {
/* Change styles when `posts` container has an orange background */
.post {
color: #fff;
}
}
That’s a pretty dumb example. One thing to note is that the container-type
is no longer based on the container’s inline-size
but by style
. We could delcare that like so:
.posts {
container-name: posts;
container-type: style; /* unnecessary */
}
…but all container queries are style
queries by default. Well. at least as it stands today. Miriam Suzanne has a nice outline of the possible issues that might pop up with that.
Where might querying a container’s styles come in handy? I don’t know yet! But my mind goes to a few places:
- Custom property values: We’ve seen custom properties used like state indicators, such as the DRY-switching method Ana covered a while back. The value changes, and so do styles.
- Alternate dark mode approach: Instead of basing it all on a body class change that re-assigns custom property values, maybe we can change an entire color palette if, say, the body background changes color.
- More complex query conditions: Like, say, we want to apply styles when the
size
andstyle
conditions for a container are met.
Una also mentioned in the CSS Podcast that container style queries could help prevent some awkward styling situations, like if we happen to have italicized text in an already italicized blockquote
:
blockquote {
container-name: quote;
}
@container quote (font-style: italic) {
em, i, q, address {
font-style: normal;
}
}
seems unnecessarily convoluted. why not:
@container .posts (min-width: 600px) {
// applies to .posts
}
not snark, really trying to find the logic…
That would be super cool and much more efficient. But I also get that there are things that CSS has to know up front, and one of those things is being able to match a container declaration to an element that’s explcitly defined as a container — not to mention what kind of query we want, whether it’s the size or style of that container. We have to tell CSS that so the browser knows how to match things up.
Selector “.posts” could theoretically target multiple HTML nodes, each having the attribute class set to posts. In that case it wouldn’t be obvious to determine which container’s width should be checked in the query.
I can imagine that the CSS property “container-name” serves to make sure that there can only be a single container with a given name.
My guess is
.post
andcontainer-name: posts;
happen to use the same name in the example but in real world cases this doesn’t have to be the case and the samecontainer-name
will be used in multiple class selectors.The replies here capture some of the reasons. Like Geoff suggests, we need to establish containers explicitly – so there’s no avoiding that step, even if we used selectors in the
@container
syntax.But also, names are optional, reusable across different elements, and one container can have multiple names. This adds a lot of flexibility.
You don’t have to give containers a name, and you don’t have to mention a name in the query syntax. When no name is added to the condition, the nearest valid ancestor container is queried. If you just want to know the most directly relevant context, leave off the name.
You can apply the same name to multiple selectors to create a ‘class’ of container. So you could add the
layout
container name to the main area, the sidebar, posts, grid items, etc. Then you can query the nearestlayout
container.You can apply multiple names to a single container, to make it part of multiple patterns. So we could say the main area is a container that is part of our
layout
pattern, but also give it the namemain
, and the namecolor-context
because it applies a unique color scheme. Now we can write some queries specific to themain
area name, some looking for the nearestlayout
, and some looking at the nearestcolor-context
– and the main area is set up to handle all those queries.