Archived:
✅ This feature has shipped in browsers. Our notes are likely out-of-date.
The overall approach documented in my initial Proposal & Explainer has been approved by the CSSWG – but there is still some interest in adding explicit new syntax for establishing containment, as well as new container-relative units.
General terminology ¶
CSS already has many different types of containers,
containment, containing blocks, etc.
That doesn’t necessarily mean
we have to avoid the term “container” entirely –
at this point we’re leaning into it with @container
–
but it does mean we need to define terms carefully.
These are a few of the essential parts, and the names I’m currently using for them:
- Container Query:
Refers to the entire
@container
rule block - Query Container: An element with appropriate containment (or whatever else is required) to be observed by a container query.
- Containment Context: Context generated by the query container, which applies to all descendants until any nested query container establishes a new context.
- Querying Element: Any element targeted by a selector inside of a container query. The element queries the containment context established by its nearest ancestor container.
- Nearest Ancestor Container: The specific query container that is generating the current containment context for a given querying element.
The word “container” is already used
quite often in CSS, but never on its own.
Still, there are potential confusions with the term –
especially if we want a new container
property
in addition to the existing contain
property.
So I
asked twitter
to help brainstorm additional terms:
- People often say “element queries” but “element” already has a much too generic meaning
- component?
- module?
- context?
- structure?
- viewbox?
- enclosure?
- compartment?
- Parent?
Despite the issues,
I’ll continue using container
for now –
since it’s the name
most people have used for this feature
since ~2010.
But context
stands out to me
as a reasonable alternative.
Proposed syntax for containers ¶
I’m proposing a new set of container
properties:
container-type
: the type of container neededcontainer-name
: custom name(s) for the containercontainer
: a shorthand syntax
These properties would:
- Explicitly establish the element as a container
- Establish the types of queries allowed on the container
(e.g.
inline-size
) so that the browser can apply the minimum containment (if any) required to make those query types possible - Give the container a name, which can be referenced in queries.
Container types ¶
Right now we’re focused on two query types:
size
queries (withblock-size
orinline-size
options)style
queries
We’ve also discussed
state queries,
there is still debate about
using @container
or some form of selector syntax
for those use-cases.
I expect that will be pushed
to the next level of the specification.
Container names ¶
By default the @container
rule will try to use
the nearest available container,
but nested containers of different types could get in the way.
Naming containers will allow authors
to ensure they are querying the intended containers.
(This syntax is still a work in progress. See the shorthand section for details)
main, section {
container: inline-size / layout-system;
}
.my-component {
container: style / framework;
}
@container layout-system (inline-size >= 30em ) { /* … */ }
@container framework (font-size >= 2rem) { /* … */ }
For queries that require a named ancestor, but do not require any form of containment, it might be enough to set a query name without setting a type.
Container shorthand & query syntax ¶
See issue #6393
Name and type need a combined syntax in the shorthand property,
and also in the @container
rule.
It would be great to have one shared syntax across both locations.
Our current (prototyped) shorthand property syntax
relies on consistent order,
and the /
divider (eg types / names
).
But that was based on the assumption that a type is always required,
and I don’t think that’s a reliable assumption.
Type is clearly not required for the query syntax,
and style queries could make it optional for the container as well.
Still, the ordered approach is a valid option. In order to make that work with both sides optional, the delimiter needs to be used for all names, even when no type is given. Either using punctuation or a keyword:
/* using the current `/` divider */
@container inline-size / my-name ( width > 30em ) { … }
@container inline-size ( width > 30em ) { … }
@container / my-name ( width > 30em ) { … }
/* using a single keyword, still ordered */
@container inline-size as my-name ( width > 30em ) { … }
@container inline-size ( width > 30em ) { … }
@container as my-name ( width > 30em ) { … }
But I’d love a more flexible approach.
We could make order irrelevant
by adding a second keyword ('for' <types> || 'as' <names>
):
@container for inline-size as my-name ( width > 30em ) { … }
@container as my-name for inline-size ( width > 30em ) { … }
@container for inline-size ( width > 30em ) { … }
@container as my-name ( width > 30em ) { … }
But the more I stare at this, the more tempted I am to just use dashed-idents for names, and allow the two values to mingle completely:
@container inline-size --my-name ( width > 30em ) { … }
@container --my-name inline-size ( width > 30em ) { … }
@container inline-size ( width > 30em ) { … }
@container --my-name ( width > 30em ) { … }
That might also allow us to express and/or combinations
(maybe with the /
divider
between container-selection
and query logic – if that division needs more clarity):
@container inline-size and --my-name / ( width > 30em ) { … }
@container (--my-name or --other-name) / ( width > 30em ) { … }
We could consider adding parenthesis around any of these options, if it helps.