1. 简介
本文档是 CSS 包含级别 2 的差异规范。它目前处于探索性工作草案阶段:如果您正在进行实现,请以级别 2 作为参考。一旦达到 CR(候选推荐标准)阶段,我们将把级别 2 的文本合并到本草案中。
1.1. 模块交互
本文档定义了早期规范中不存在的新功能。此外,它旨在稳定后取代并超越 [CSS-CONTAIN-1]。
1.2. 值定义
本规范遵循 CSS 属性定义约定([CSS2]),使用 值定义语法([CSS-VALUES-3])。本规范未定义的值类型在 CSS Values & Units [CSS-VALUES-3] 中定义。与其他 CSS 模块的组合可能会扩展这些值类型的定义。
除了定义中列出的属性特定值外,本规范中定义的所有属性也都接受 CSS 全局关键字 作为其属性值。为了可读性,未明确重复列出。
2. 强包含:contain 属性
| 名称 | contain |
|---|---|
| 新值 | layout || style || paint || [ size | inline-size ] |
- inline-size
- 此值开启该元素的内联尺寸包含。这防止了其主体盒 (principal box) 的内联尺寸直接依赖于其内容。
注意:仍然可能存在间接依赖关系,请参阅 § 3.1 内联尺寸包含。
3. 封装类型
3.1. 内联尺寸包含
为元素赋予内联尺寸包含,会将尺寸包含应用于其主体盒的内联轴 (inline-axis) 尺寸调整。这意味着内联轴固有尺寸 (intrinsic sizes) 的主体盒被确定的方式就好像该元素没有内容一样。然而,内容会继续照常影响盒子的块级轴 (block-axis) 固有尺寸,并且该盒子被允许在块级轴上正常分片 (fragment)。
例如,如果引入了滚动条,即使随后的块级尺寸足够小而不需要它们,也不会将其移除;或者如果一个盒子的逻辑高度与下方放置的浮动元素碰撞,并被清除到它也拥有更多可用内联空间且因此变得足够短而没有碰撞的位置,它也不会被移回其先前出现问题的尺寸和位置。
因此,尽管内联尺寸包含防止了盒子的内容通过其内联轴固有尺寸直接影响其内联尺寸,但其内联尺寸仍可能通过内容对其块级尺寸的影响而间接依赖于其内容。
通常,元素的内联尺寸与其块级尺寸之间的关系是不可预测且非单调的,块级尺寸可能会随着内联尺寸的改变而任意上下移动。通过确保布局不会回退到先前的(已知有问题的)状态来防止无限循环,即使对约束的简单分析允许这样做;换句话说,布局总是“向前移动”。我们相信当前的 CSS 布局规范包含了此类规则,但如果在某些范围内未包含,请通知 CSSWG,以便纠正这些错误。
< 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 >
块级布局算法将首先放置浮动框,前两个位于容器的左角和右角,第三个因为太宽而无法容纳在中间,被推到它们下方。
接下来的 article 将被布局。因为它被设置为 display: flow-root,它不能与任何浮动相交,因此在计算如何调整自身尺寸和位置时必须将它们考虑在内。
布局引擎首先尝试将 article 与容器顶部对齐放置,导致 100px 的宽度,这足够宽以容纳其最小内容尺寸。然而,由于其子元素的纵横比,这也会导致 article 的高度为 100px,这将与下方 80px 处的第三个浮动元素相交,因此该布局方案被丢弃。
然后它尝试将 article 与第三个浮动元素的顶部对齐,放置在其右侧 40px 宽的狭窄空间中。然而,由于 article 的最小宽度使其太大而无法放入第三个浮动元素旁边的 40px 宽空间,它也移动到了该元素下方,在所有浮动框下方形成了一个 200px 的正方形。
如果从 article 中移除最小宽度,或者如果将内联尺寸包含添加到 article 或 header(导致 min-width: min-content 解析为零),那么 article 将作为 40px 的正方形放入最后一个浮动 div 的旁边(内容可能会溢出)。
此时,article 的宽度和高度(各 40px)*将*能回到之前考虑的空间,与容器顶部对齐。然而,该盒子不会回到之前的位置,因为布局引擎已经知道该位置会导致无效布局。
如果以下任何条件成立,赋予元素内联尺寸包含将无效:
-
如果该元素没有生成主体盒(例如 display: contents 或 display: none 的情况)
4. 容器查询
虽然媒体查询提供了一种查询文档显示环境(如视口尺寸或用户偏好)的方法,但容器查询允许测试文档中元素的内容(如盒子尺寸或计算样式)。
默认情况下,所有元素都是用于容器样式查询的查询容器,并可以通过使用 container-type 属性(或 container 简写属性)指定额外的查询类型,确立为容器尺寸查询的查询容器。应用于查询容器的包含 Shadow DOM 的后代的样式规则,可以通过使用 @container 条件组规则对其进行查询来加以限定。
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 ; } }
主内容区和侧边栏中的媒体对象将各自响应其自身的容器上下文。
对于带有伪元素的选定器,查询容器可以由包含 Shadow DOM 的包含祖先确立,作为最终起源元素。
-
伪元素本身不能成为查询容器
-
::before、::after、::marker 和 ::backdrop 查询它们的起源元素
-
::first-letter 和 ::first-line 查询它们的起源元素,即使虚构标记序列可能为了继承和渲染的目的将
::first-line推到其他元素之后 -
多个伪元素不允许伪元素成为其他伪元素的查询容器。例如,
host::part()::before中的宿主可以作为::before的查询容器,但::part()不能。同样,div::before::marker中的::before不能作为::marker的查询容器 -
::slotted() 选择器可以查询阴影树内部的容器,包括插槽本身
-
::part() 选择器可以查询其起源宿主,但不能查询阴影树内部的查询容器
-
::placeholder 和 ::file-selector-button 可以查询输入元素,但如果输入元素是使用阴影树实现的,它们不会暴露任何内部容器
< 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. 创建查询容器:container-type 属性
| 名称 | container-type |
|---|---|
| 值 | normal || [ size | inline-size ] |
| 初始值 | normal |
| 应用于 | 所有元素 |
| 可继承 | 否 |
| 百分比 | 不可用 |
| 计算值 | 关键字 normal 或 size、inline-size 中的一个或多个 |
| 规范顺序 | 按语法 |
| 动画类型 | 不可动画 |
container-type 属性将元素确立为查询容器,用于需要显式包含(例如容器尺寸查询)的容器查询,允许对后代进行样式化的样式规则查询其尺寸和布局的各个方面,并做出相应的响应。
除非另有说明,所有元素都是用于无需显式包含(例如容器样式查询)的容器查询的查询容器,无论指定的 container-type 如何。
值的含义如下:
- size
- 为容器尺寸查询确立一个在内联轴和块级轴上的查询容器。将布局包含、样式包含和尺寸包含应用于主体盒。
- inline-size
- 为容器自身内联轴上的容器尺寸查询确立一个查询容器。将布局包含、样式包含和内联尺寸包含应用于主体盒。
- normal
- 该元素不是任何容器尺寸查询的查询容器,但仍然是容器样式查询的查询容器。
aside, main{ container-type : inline-size; } h2{ font-size : 1.2 em ; } @container ( width >40 em ) { h2{ font-size : 1.5 em ; } }
section{ container-type : style; } @container ( --cards: small) { article{ border : thin solid silver; border-radius : 0.5 em ; padding : 1 em ; } }
4.2. 命名查询容器:container-name 属性
| 名称 | container-name |
|---|---|
| 值 | none | <custom-ident>+ |
| 初始值 | none(无) |
| 应用于 | 所有元素 |
| 可继承 | 否 |
| 百分比 | 不可用 |
| 计算值 | 关键字 none,或标识符的有序列表 |
| 规范顺序 | 按语法 |
| 动画类型 | 不可动画 |
container-name 属性指定了查询容器名称的列表。这些名称可以被 @container 规则用于过滤目标查询容器。
- none(无)
- 查询容器没有查询容器名称。
- <custom-ident>
- 将查询容器名称指定为标识符。关键字 none、and、not 和 or 从此 <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. 创建命名容器:container 简写属性
| 名称 | container |
|---|---|
| 值 | <'container-name'> [ / <'container-type'> ]? |
| 初始值 | 见各个属性 |
| 应用于 | 见各个属性 |
| 可继承 | 见各个属性 |
| 百分比 | 见各个属性 |
| 计算值 | 见各个属性 |
| 动画类型 | 见各个属性 |
| 规范顺序 | 按语法 |
container 简写属性在同一声明中同时设置 container-type 和 container-name。如果省略 <'container-type'>,它将被重置为其初始值。
main{ container : my-layout / size; } .grid-item{ container : my-component / inline-size; }
4.4. 容器查询:@container 规则
@container 规则是一个条件组规则,其条件是一个容器查询,它是容器尺寸查询和/或容器样式查询的布尔组合。@container 规则的 <stylesheet> 块内的样式声明由其条件过滤,仅当容器查询对其元素的查询容器为真时才匹配。
@container 规则的语法是
@container [ <container-name> ]? <container-condition> {
<stylesheet>
}
其中
<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>
关键字 none、and、not 和 or 从上面的 <custom-ident> 中排除。
对于每个元素,要查询的查询容器是从元素的祖先查询容器中选择的,这些祖先必须为 <container-condition> 中的所有容器特性确立为有效的查询容器。可选的 <container-name> 将考虑的查询容器集合过滤为仅那些具有匹配的查询容器名称的容器。
一旦为元素选择了合格的查询容器,<container-condition> 中的每个容器特性都会针对该查询容器进行评估。如果没有祖先是合格的查询容器,则对于该元素,容器查询为 unknown。
@container card( inline-size >30 em ) andstyle ( --responsive: true) { /* styles */ }
定义在多个嵌套容器查询内部的元素上的样式规则,在该元素的所有外层容器查询都为真时应用。
注意:嵌套的容器查询可以相对于不同的容器进行评估,因此并不总是能够将单独的 <container-condition> 合并为一个查询。
@container card( inline-size >30 em ) { @container style ( --responsive: true) { /* styles */ } }
在容器查询内部定义的全局名称定义预定义规则(如 @keyframes、@font-face 或 @layer)不受容器查询条件的约束。
4.5. 动画容器
容器查询评估的变化必须是样式变更事件的一部分,即使这种变化是由于动画效果引起的。
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 >
由容器查询长度单位引起的计算值的变化也必须是样式变更事件的一部分。
5. 容器特性
5.1. 尺寸容器特性
一个容器尺寸查询允许查询查询容器的主体盒的尺寸。它是单独尺寸特性(<size-feature>)的布尔组合,每个特性查询查询容器的单个特定维度特性。<size-feature> 的语法与媒体特性相同:特性名称、比较器和值。[mediaqueries-5] 将尺寸特性组合成尺寸查询的布尔语法和逻辑与CSS 特性查询相同。(参见 @supports。[CSS-CONDITIONAL-3])
如果查询容器没有主体盒,或者主体盒不是布局包含盒,或者查询容器不支持相关轴上的容器尺寸查询,则评估尺寸特性的结果为 unknown。
相对长度单位(包括容器查询长度单位)在容器查询条件中根据查询容器的计算值进行评估。
注意:这与媒体查询中相对单位的处理方式不同。
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 ; } }
查询条件中使用的 40em 值相对于相关查询容器上的 font-size 的计算值
-
对于 aside 内部的任何 h2,查询条件在 640px 以上时为真。
-
对于 main 内部的任何 h2,查询条件在 960px 以上时为真。
5.1.1. 宽度:width 特性
| 名称 | width |
|---|---|
| 对于 | @container |
| 值 | <length>(长度) |
| 类型 | 值域 (range) |
width 容器特性查询查询容器的主体盒的内容盒 (content box) 宽度。
5.1.2. 高度:height 特性
| 名称 | height |
|---|---|
| 对于 | @container |
| 值 | <length>(长度) |
| 类型 | 值域 (range) |
5.1.3. 内联尺寸:inline-size 特性
| 名称 | inline-size |
|---|---|
| 对于 | @container |
| 值 | <length>(长度) |
| 类型 | 值域 (range) |
inline-size 容器特性查询查询容器的内容盒在查询容器的内联轴上的尺寸。
5.1.4. 块级尺寸:block-size 特性
| 名称 | block-size |
|---|---|
| 对于 | @container |
| 值 | <length>(长度) |
| 类型 | 值域 (range) |
block-size 容器特性查询查询容器的内容盒在查询容器的块级轴上的尺寸。
5.1.5. 纵横比:aspect-ratio 特性
| 名称 | aspect-ratio |
|---|---|
| 对于 | @container |
| 值 | <ratio> |
| 类型 | 值域 (range) |
aspect-ratio 容器特性定义为 width 容器特性的值与 height 容器特性的值之比。
5.1.6. 方向:orientation 特性
| 名称 | orientation |
|---|---|
| 对于 | @container |
| 值 | portrait | landscape |
| 类型 | 离散 (discrete) |
- portrait
- 当 height 容器特性的值大于或等于 width 容器特性的值时,orientation 容器特性为 portrait。
- landscape
- 否则 orientation 为 landscape。
5.2. 样式容器特性
一个容器样式查询允许查询查询容器的计算值。它是单独样式特性(<style-feature>)的布尔组合,每个特性查询查询容器的单个特定属性。<style-feature> 的语法与声明相同。[CSS-SYNTAX-3],如果查询容器上给定属性的计算值与给定值匹配(该值也相对于查询容器进行计算),则其查询为真;如果属性或其值无效或不受支持,则为未知;否则为假。将样式特性组合成样式查询的布尔语法和逻辑与CSS 特性查询相同。(参见 @supports。[CSS-CONDITIONAL-3])
查询简写属性的样式特性,如果其每个长写属性的计算值匹配,则为真,否则为假。
级联依赖关键字(如 revert 和 revert-layer)作为样式特性中的值是无效的,会导致容器样式查询为假。
注意:其余非级联依赖的CSS 范围关键字相对于查询容器进行计算,与其他值相同。
6. 容器相对长度:cqw、cqh、cqi、cqb、cqmin、cqmax 单位
容器查询长度单位指定相对于查询容器尺寸的长度。使用容器查询长度单位的样式表可以更容易地将组件从一个查询容器移动到另一个。
容器查询长度单位为
| unit | 相对于 |
|---|---|
| cqw | 查询容器宽度的 1% |
| cqh | 查询容器高度的 1% |
| cqi | 查询容器内联尺寸的 1% |
| cqb | 查询容器块级尺寸的 1% |
| cqmin | cqi 或 cqb 中的较小值 |
| cqmax | cqi 或 cqb 中的较大值 |
对于每个元素,容器查询长度单位被评估为单位所描述的相关轴(或多个轴)上的容器尺寸查询。每个轴的查询容器是接受该轴上容器尺寸查询的最近祖先容器。如果没有可用的合格查询容器,则使用该轴的小视口尺寸。
注意:在某些情况下,同一元素上的 cqi 和 cqb 单位将相对于不同的查询容器进行评估。同样,cqmin 和 cqmax 单位表示 cqi 和 cqb 单位的较大或较小值,即使这些尺寸来自不同的查询容器。
子元素不会继承为其父元素指定的相对值;它们继承计算值。
/* 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. API
7.1. CSSContainerRule 接口
CSSContainerRule 接口代表一个 @container 规则。
[Exposed =Window ]interface :CSSContainerRule CSSConditionRule { };
conditionText类型为CSSOMString(CSSContainerRule 对 CSSConditionRule 上属性的特定定义)conditionText属性(定义在CSSConditionRule父规则上),在获取时,必须返回指定的条件,不包含任何逻辑简化,以便返回的条件在符合本规范的任何实现中(包括实现本规范中允许的 <general-enclosed> 可扩展性机制的实现)都将评估为与指定条件相同的结果。换句话说,允许标记流简化(例如将空白减少为单个空格或在已知为可选的情况下省略),但不允许逻辑简化(例如删除不必要的括号或基于评估结果的简化)。
为 CSSContainerRule 添加 CSSOM API [Issue #7033]
容器查询应具有 matchContainer 方法。这将参照 matchMedia() 和 MediaQueryList 接口进行建模,但应用于元素而不是 Window。在测量布局大小时,它的行为类似于 resizeObserver,但它提供了额外的容器查询语法和功能。[Issue #6205]
8. 完全抑制元素内容:content-visibility 属性
CSS 包含 2 § 4 完全抑制元素内容:content-visibility 属性
9. 隐私与安全注意事项
附录 A. 变更
本附录是信息性的。
自 2021 年 12 月 21 日首份公开工作草案以来的变更
自 2021 年 12 月 21 日首份公开工作草案以来的重大变更包括
-
允许 container-name 的计算值包含重复的标识符。(Issue 7181)
-
使 container 简写属性中的 <'container-name'> 成为必填项。(Issue 7142)
-
澄清容器样式查询中对简写属性的处理。(Issue 7095)
-
级联依赖关键字不允许作为样式特性中的值,并导致容器样式查询为假。(Issue 7080)
-
将 container-type 的初始值更改为 style。(Issue 6393)
-
从 container-type 中移除 block-size 值,因为目前无法实现单轴 block-size 包含。(Issue 1031)
-
从 container-name 语法中移除 <string> 选项。容器名称必须是 <custom-ident>。(Issue 6405)
-
在 container 简写属性中反转 <'container-name'> 和 <'container-type'> 的顺序,两者均为可选。(Issue 6393)
-
为了向前兼容,允许在 <container-condition> 中使用 <general-enclosed> 语法。(Issue 6396)
-
从 <size-feature> 查询中移除尺寸函数语法。(Issue 6870)
-
更新查询容器选择过程以说明必要的 container-types,并移除显式类型选择语法。(Issue 6644)
-
移除已推迟的状态查询特性。(Issue 6402)
-
澄清伪元素和影子 DOM 周围的容器选择。(Issue 5984 和 Issue 6711)
自 CSS 包含级别 2 以来的变更
致谢
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 等人的评论和早期工作为本规范做出了贡献。