Explicit Container Syntax

Table of Contents

✅ 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:

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:

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:

These properties would:

Container types

Right now we’re focused on two query types:

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.