1. Introduction
This is a diff spec over CSS Containment Level 2. It is currently an Exploratory Working Draft: if you are implementing anything, please use Level 2 as a reference. We will merge the Level 2 text into this draft once it reaches CR.
1.1. Module Interactions
This document defines new features not present in earlier specifications. In addition, it aims to replace and supersede [CSS-CONTAIN-1] once stable.
1.2. Value Definitions
This specification follows the CSS property definition conventions from [CSS2] using the value definition syntax from [CSS-VALUES-3]. Value types not defined in this specification are defined in CSS Values & Units [CSS-VALUES-3]. Combination with other CSS modules may expand the definitions of these value types.
In addition to the property-specific values listed in their definitions, all properties defined in this specification also accept the CSS-wide keywords as their property value. For readability they have not been repeated explicitly.
2. Strong Containment: the contain property
CSS Containment 2 § 2 Strong Containment: the contain property
Name: | contain |
---|---|
New values: | layout || style || paint || [ size | inline-size ] |
- inline-size
-
This value turns on inline-size containment for the element.
This prevents the inline-size of its principal box from directly depending on its contents.
Note: There can still be indirect dependencies, see § 3.1 Inline-Size Containment.
3. Types of Containment
CSS Containment 2 § 3 Types of Containment
3.1. Inline-Size Containment
Giving an element inline-size containment applies size containment to the inline-axis sizing of its principal box. This means the inline-axis intrinsic sizes of the principal box are determined as if the element had no content. However, content continues to impact the box’s block-axis intrinsic sizes as usual, and the box is allowed to fragment normally in the block axis.
For example, if scrollbars were introduced, they are not then removed, even if the consequent block size is small enough to not need them; or if a box’s logical height collides with a lower-placed float and is cleared down to where it also has more available inline space and thus becomes short enough to not have collided, it is not them moved back up to its previous problematic size and position.
Thus, although inline-size containment prevents the box’s content from directly affecting its inline size through its inline-axis intrinsic sizes, its inline size can still indirectly depend on its contents by their effect on its block size.
In general, the relationship between an element’s inline size and it’s block size is unpredictable and non-monotonic, with the block size capable of shifting up and down arbitrarily as the inline size is changed. Infinite cycles are prevented by ensuring that layout does not revert to a previous (known-problematic) state, even if a naive analysis of the constraints would allow for such; in other words, layout always “moves forward”. We believe that current CSS layout specifications incorporate such rules, but to the extent that they don’t, please inform the CSSWG so that these errors can be corrected.
< section style = "width: 200px; border: solid; display: flow-root;" > < div style = "float: left; width: 50px; height: 80px; background: blue;" ></ div > < div style = "float: right; width: 50px; height: 80px; background: blue;" ></ div > < div style = "float: left; width: 160px; height: 80px; background: navy;" ></ div > < article style = "border: solid orangered; display: flow-root; min-width: min-content" > < div style = "background: orange; aspect-ratio: 1/1;" > Article</ div > </ article > </ section >
The block layout algorithm will first place the floating boxes, with the first two sitting in the left and right corners of the container, and the third, being too wide to fit between, being pushed below them.
The following article
will then be laid out.
Because it is display: flow-root,
it cannot intersect any floats,
and thus must take them into account
when figuring out how to size and position itself.
The layout engine first attempts to place the article
flush with the top of the container,
resulting a 100px width,
plenty wide enough to accommodate its min-content size.
However, due to the aspect-ratio of its child,
this would cause the article
to be 100px tall as well,
which would intersect the third float 80px below,
so this layout opportunity is discarded.
It then attempts to position the article
flush with the top of the third float,
in the narrow 40px-wide space to its right.
However, since the article
’s min-width makes it too large
to fit in the 40px-wide space beside the third float,
it shifts below that one as well,
forming a 200px square below all the floated boxes.
If the min-width is removed from the article
,
or if inline-size containment is added to
either the article
or header
(causing min-width: min-content to resolve to zero),
then the article
will fit as a 40px square
next to the final floated div
(possibly with some of its content overflowing).
At this point, the width and height of the article
(40px each) would fit back in the first considered space,
flush with the top of the container.
However, the box is not returned to the previous position,
because the layout engine knows already
that this position would result in an invalid layout.
Giving an element inline-size containment has no effect if any of the following are true:
-
if the element does not generate a principal box (as is the case with display: contents or display: none)
-
if its inner display type is table
-
if its principal box is an internal table box
-
if its principal box is an internal ruby box or a non-atomic inline-level box
4. Container Queries
While media queries provide a method to query aspects of the user agent or device environment that a document is being displayed in (such as viewport dimensions or user preferences), container queries allow testing aspects of elements within the document (such as box dimensions or computed styles).
By default, all elements are query containers for the purpose of container style queries, and can be established as query containers for container size queries by specifying the additional query types using the container-type property (or the container shorthand). Style rules applying to a query container’s shadow-including descendants can be conditioned by querying against it, using the @container conditional group rule.
main, aside{ container : my-layout / inline-size; } .media-object{ display : grid; grid-template : 'img' auto'content' auto /100 % ; } @container my-layout( inline-size >45 em ) { .media-object{ grid-template : 'img content' auto / auto1 fr ; } }
Media objects in the main and sidebar areas will each respond to their own container context.
For selectors with pseudo elements, query containers can be established by the shadow-including inclusive ancestors of the ultimate originating element.
-
Pseudo elements themselves can not be query containers
-
::before, ::after, ::marker, and ::backdrop query their originating elements
-
::first-letter and ::first-line query their originating elements, even if the fictional tag sequence may push the
::first-line
past other elements for the purpose of inheritance and rendering -
Multiple pseudo elements do not allow pseudo elements to be query containers for other pseudo elements. E.g., the host, but not the
::part()
, can be the query container for::before
inhost::part()::before
. Similarly,::before
can not be the query container for the::marker
indiv::before::marker
-
::slotted() selectors can query containers inside the shadow tree, including the slot itself
-
::part() selectors can query its originating host, but not internal query containers inside the shadow tree
-
::placeholder and ::file-selector-button can query the input element, but do not expose any internal containers if the input element is implemented using a shadow tree
< style > # container { width : 100 px ; container-type : inline - size ; } @ container ( inline-size < 150px ) { # inner :: before { content : "BEFORE" ; } } </ style > < div id = container > < span id = inner ></ span > </ div >
< div id = host style = "width:200px" > < template shadowroot = open > < style > # container { width : 100 px ; container-type : inline - size ; } @ container ( inline-size < 150px ) { :: slotted ( span ) { color : green ; } } </ style > < div id = container > < slot /> </ div > </ template > < span id = slotted > Green</ span > </ div >
4.1. Creating Query Containers: the container-type property
Name: | container-type |
---|---|
Value: | normal || [ size | inline-size ] |
Initial: | normal |
Applies to: | all elements |
Inherited: | no |
Percentages: | n/a |
Computed value: | the keyword normal or one or more of size, inline-size |
Canonical order: | per grammar |
Animation type: | not animatable |
The container-type property establishes the element as a query container for the purpose of container queries that require explicit containment (such as container size queries), allowing style rules styling its descendants to query various aspects of its sizing and layout, and respond accordingly.
Unless otherwise noted, all elements are query containers for the purpose container queries that do no require explicit containment (such as container style queries), reagardless of the specified container-type.
Values have the following meanings:
- size
- Establishes a query container for container size queries on both the inline and block axis. Applies layout containment, style containment, and size containment to the principal box.
- inline-size
- Establishes a query container for container size queries on the container’s own inline axis. Applies layout containment, style containment, and inline-size containment to the principal box.
- normal
- The element is not a query container for any container size queries, but remains a query container for container style queries.
aside, main{ container-type : inline-size; } h2{ font-size : 1.2 em ; } @container ( width >40 em ) { h2{ font-size : 1.5 em ; } }
The 40em value used in the query condition is relative to the computed value of font-size on the relevant query container.
section{ container-type : style; } @container ( --cards: small) { article{ border : thin solid silver; border-radius : 0.5 em ; padding : 1 em ; } }
4.2. Naming Query Containers: the container-name property
Name: | container-name |
---|---|
Value: | none | <custom-ident>+ |
Initial: | none |
Applies to: | all elements |
Inherited: | no |
Percentages: | n/a |
Computed value: | the keyword none, or an ordered list of identifiers |
Canonical order: | per grammar |
Animation type: | not animatable |
The container-name property specifies a list of query container names. These names can be used by @container rules to filter which query containers are targeted.
- none
- The query container has no query container name.
- <custom-ident>
- Specifies a query container name as an identifier. The keywords none, and, not, and or are excluded from this <custom-ident>.
main{ container-type : size; container-name : my-page-layout; } .my-component{ container-type : inline-size; container-name : my-component-library; } @container my-page-layout( block-size >12 em ) { .card{ margin-block : 2 em ; } } @container my-component-library( inline-size >30 em ) { .card{ margin-inline : 2 em ; } }
4.3. Creating Named Containers: the container shorthand
Name: | container |
---|---|
Value: | <'container-name'> [ / <'container-type'> ]? |
Initial: | see individual properties |
Applies to: | see individual properties |
Inherited: | see individual properties |
Percentages: | see individual properties |
Computed value: | see individual properties |
Animation type: | see individual properties |
Canonical order: | per grammar |
The container shorthand property sets both container-type and container-name in the same declaration. If <'container-type'> is omitted, it is reset to its initial value.
main{ container : my-layout / size; } .grid-item{ container : my-component / inline-size; }
4.4. Container Queries: the @container rule
The @container rule is a conditional group rule whose condition is a container query, which is a boolean combination of container size queries and/or container style queries. Style declarations within the <stylesheet> block of an @container rule are filtered by its condition to only match when the container query is true for their element’s query container.
The syntax of the @container rule is:
@container [ <container-name> ]? <container-condition> { <stylesheet> }
where:
<container-name> = <custom-ident> <container-condition> = not <query-in-parens> | <query-in-parens> [ [ and <query-in-parens> ]* | [ or <query-in-parens> ]* ] <query-in-parens> = ( <container-condition> ) | ( <size-feature> ) | style( <style-query> ) | <general-enclosed> <style-query> = <style-condition> | <style-feature> <style-condition> = not <style-in-parens> | <style-in-parens> [ [ and <style-in-parens> ]* | [ or <style-in-parens> ]* ] <style-in-parens> = ( <style-condition> ) | ( <style-feature> ) | <general-enclosed>
The keywords none, and, not, and or are excluded from the <custom-ident> above.
For each element, the query container to be queried is selected from among the element’s ancestor query containers that are established as a valid query container for all the container features in the <container-condition>. The optional <container-name> filters the set of query containers considered to just those with a matching query container name.
Once an eligible query container has been selected for an element, each container feature in the <container-condition> is evaluated against that query container. If no ancestor is an eligible query container, then the container query is unknown for that element.
@container card( inline-size >30 em ) andstyle ( --responsive: true) { /* styles */ }
The styles above will only be applied if there is an ancestor container named "card" that meets both the inline-size and style conditions.
Style rules defined on an element inside multiple nested container queries apply when all of the wrapping container queries are true for that element.
Note: Nested container queries can evaluate in relation to different containers, so it is not always possible to merge the individual <container-condition>s into a single query.
@container card( inline-size >30 em ) { @container style ( --responsive: true) { /* styles */ } }
The styles above will only be applied if there is an ancestor container named "card" that meets the inline-size condition, as well as an ancestor container meeting style condition.
Global, name-defining at-rules such as @keyframes or @font-face or @layer that are defined inside container queries are not constrained by the container query conditions.
4.5. Animated Containers
A change in the evaluation of a container query must be part of a style change event, even when the change occurred because of animation effects.
main{ display : flex; width : 300 px ; } #container{ container-type : inline-size; flex : 1 ; } /* Resolved width is initially 200px, but changes as the transition on #sibling progresses. */ #inner{ transition : 1 s background-color; background-color : tomato; } /* When this container query starts (or stops) applying, a transition must start on background-color on #inner. */ @container ( width <=150 px ) { #inner{ background-color : skyblue; } } #sibling{ width : 100 px ; transition : width1 s ; } #sibling:hover{ width : 200 px ; }
< main > < div id = container > < div id = inner > Inner</ div > </ div > < div id = sibling > Sibling</ div > </ main >
Changes in computed values caused by container query length units must also be part of a style change event.
5. Container Features
A container feature queries a specific aspect of a query container.
5.1. Size Container Features
A container size query allows querying the size of the query container’s principal box. It is a boolean combination of individual size features (<size-feature>) that each query a single, specific dimensional feature of the query container. The syntax of a <size-feature> is the same as for a media feature: a feature name, a comparator, and a value. [mediaqueries-5] The boolean syntax and logic combining size features into a size query is the same as for CSS feature queries. (See @supports. [CSS-CONDITIONAL-3])
If the query container does not have a principal box, or the principal box is not a layout containment box, or the query container does not support container size queries on the relevant axes, then the result of evaluating the size feature is unknown.
Relative length units (including container query length units) in container query conditions are evaluated based on the the computed values of the query container.
Note: This is different from the handling of relative units in media queries.
aside, main{ container-type : inline-size; } aside{ font-size : 16 px ; } main{ font-size : 24 px ; } @container ( width >40 em ) { h2{ font-size : 1.5 em ; } }
The 40em value used in the query condition is relative to the computed value of font-size on the relevant query container:
-
For any h2 inside aside, the query condition will be true above 640px.
-
For any h2 inside main, the query condition will be true above 960px.
5.1.1. Width: the width feature
Name: | width |
---|---|
For: | @container |
Value: | <length> |
Type: | range |
The width container feature queries the width of the query container’s content box.
5.1.2. Height: the height feature
Name: | height |
---|---|
For: | @container |
Value: | <length> |
Type: | range |
The height container feature queries the height of the query container’s content box.
5.1.3. Inline-size: the inline-size feature
Name: | inline-size |
---|---|
For: | @container |
Value: | <length> |
Type: | range |
The inline-size container feature queries the size of the query container’s content box in the query container’s inline axis.
5.1.4. Block-size: the block-size feature
Name: | block-size |
---|---|
For: | @container |
Value: | <length> |
Type: | range |
The block-size container feature queries the size of the query container’s content box in the query container’s block axis.
5.1.5. Aspect-ratio: the aspect-ratio feature
Name: | aspect-ratio |
---|---|
For: | @container |
Value: | <ratio> |
Type: | range |
The aspect-ratio container feature is defined as the ratio of the value of the width container feature to the value of the height container feature.
5.1.6. Orientation: the orientation feature
Name: | orientation |
---|---|
For: | @container |
Value: | portrait | landscape |
Type: | discrete |
- portrait
- The orientation container feature is portrait when the value of the height container feature is greater than or equal to the value of the width container feature.
- landscape
- Otherwise orientation is landscape.
5.2. Style Container Features
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. The syntax of a <style-feature> is the same as for a declaration [CSS-SYNTAX-3], 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. [CSS-CONDITIONAL-3])
Style features that query a shorthand property are true if the computed values match for each of its longhand properties, and false otherwise.
Cascade-dependent keywords, such as revert and revert-layer, are invalid as values in a style feature, and cause the container style query to be false.
Note: The remaining non-cascade-dependent CSS-wide keywords are computed with respect to the query container, the same as other values.
6. Container Relative Lengths: the cqw, cqh, cqi, cqb, cqmin, cqmax units
Container query length units specify a length relative to the dimensions of a query container. Style sheets that use container query length units can more easily move components from one query container to another.
The container query length units are:
unit | relative to |
---|---|
cqw | 1% of a query container’s width |
cqh | 1% of a query container’s height |
cqi | 1% of a query container’s inline size |
cqb | 1% of a query container’s block size |
cqmin | The smaller value of cqi or cqb |
cqmax | The larger value of cqi or cqb |
For each element, container query length units are evaluated as container size queries on the relevant axis (or axes) described by the unit. The query container for each axis is the nearest ancestor container that accepts container size queries on that axis. If no eligible query container is available, then use the small viewport size for that axis.
Note: In some cases cqi and cqb units on the same element will evaluate in relation to different query containers. Similarly, cqmin and cqmax units represent the larger or smaller of the cqi and cqb units, even when those dimensions come from different query containers.
Child elements do not inherit the relative values as specified for their parent; they inherit the computed values.
/* The fallback value does not rely on containment */ h2{ font-size : 1.2 em ; } @container ( inline-size >=0 px ) { /* only applies when an inline-size container is available */ h2{ font-size : calc ( 1.2 em +1 cqi ); } }
7. APIs
7.1. The CSSContainerRule
interface
The CSSContainerRule
interface represents a @container rule.
[Exposed =Window ]interface :
CSSContainerRule CSSConditionRule { };
conditionText
of typeCSSOMString
(CSSContainerRule-specific definition for attribute on CSSConditionRule)- The
conditionText
attribute (defined on theCSSConditionRule
parent rule), on getting, must return the condition that was specified, without any logical simplifications, so that the returned condition will evaluate to the same result as the specified condition in any conformant implementation of this specification (including implementations that implement future extensions allowed by the <general-enclosed> extensibility mechanism in this specification). In other words, token stream simplifications are allowed (such as reducing whitespace to a single space or omitting it in cases where it is known to be optional), but logical simplifications (such as removal of unneeded parentheses, or simplification based on evaluating results) are not allowed.
Add CSSOM API for CSSContainerRule [Issue #7033]
Container Queries should have a matchContainer
method.
This will be modeled on matchMedia()
and the MediaQueryList
interface,
but applied to Elements rather than the Window.
When measuring layout sizes, it behaves Similar to resizeObserver
,
but it provides the additional Container Query syntax and features. [Issue #6205]
8. Suppressing An Element’s Contents Entirely: the content-visibility property
CSS Containment 2 § 4 Suppressing An Element’s Contents Entirely: the content-visibility property
9. Privacy and Security Considerations
CSS Containment 2 § 5 Privacy and Security Considerations
Appendix A. Changes
This appendix is informative.
Changes since the 21 December 2021 First Public Working Draft
Significant changes since the 21 December 2021 First Public Working Draft include:
-
Allow the computed value of container-name to include duplicate identifiers. (Issue 7181)
-
Make the <'container-name'> in the container shorthand required. (Issue 7142)
-
Clarify handling of shorthand properties in container style queries. (Issue 7095)
-
Cascade-dependent keywords are not allowed as values in a style feature, and cause the container style query to be false. (Issue 7080)
-
Change the initial value of container-type to be style. (Issue 6393)
-
Remove the block-size value from container-type, since single-axis block-size containment is not currently possible. (Issue 1031)
-
Remove the <string> option from the container-name syntax. Container names must be <custom-ident>s. (Issue 6405)
-
Reverse the order of <'container-name'> and <'container-type'> in the container shorthand property, with both being optional. (Issue 6393)
-
Allow <general-enclosed> syntax in <container-condition>s, for the sake of forward compatability. (Issue 6396)
-
Remove the size function syntax from <size-feature> queries. (Issue 6870)
-
Update the query container selection process to account for necessary container-types, and removed the explicit type-selection syntax. (Issue 6644)
-
Remove state query features, which have been deferred. (Issue 6402)
-
Clarify container selection around pseudo-elements and the shadow-DOM. (Issue 5984 and Issue 6711)
Changes from CSS Containment Level 2
-
Introduces inline-size containment.
-
Defines the terms, properties, units, and at-rule needed for Container Queries
Acknowledgments
Comments and previous work from Adam Argyle, Amelia Bellamy-Royds, Anders Hartvoll Ruud, Brian Kardell, Chris Coyier, Christopher Kirk-Nielsen, David Herron, Elika J. Etemad (fantasai), Eric Portis, Ethan Marcotte, Geoff Graham, Gregory Wild-Smith, Ian Kilpatrick, Jen Simmons, Kenneth Rohde Christiansen, L. David Baron, Lea Verou, Martin Auswöger, Martine Dowden, Mike Riethmuller, Morten Stenshorne, Nicole Sullivan, Rune Lillesveen, Scott Jehl Scott Kellum, Stacy Kvernmo, Theresa O’Connor, Una Kravets, and many others have contributed to this specification.