1. 介绍
高效呈现网站依赖于用户代理能够检测页面的哪些部分正在显示、哪些部分可能影响当前显示的部分,以及哪些可以被忽略。
可以使用各种启发式方法来猜测某个子树在某种程度上是否独立于页面的其余部分,但这些方法很脆弱,页面的无意更改可能会使其无法通过此类启发式检测,从而导致渲染进入较慢的代码路径。还有许多希望隔离的情况,用启发式方法难以或无法检测到。
为缓解这些问题并允许对子树与页面其余部分进行强且可预测的隔离,本规范定义了一个 contain 属性。
1.1. 值定义
本规范遵循来自 CSS 属性定义约定(来自 [CSS2])以及来自 CSS 值的值定义语法(来自 [CSS-VALUES-3])。本规范未定义的值类型在 CSS 值与单位 [CSS-VALUES-3] 中定义。与其他 CSS 模块的组合可能会扩展这些值类型的定义。
除其定义中列出的属性特定值之外,本规范中定义的所有属性也接受 CSS 全局关键字 作为它们的属性值。为可读性起见,这些关键字未在此重复列出。
2. 强包含:contain 属性
| Name: | contain |
|---|---|
| Value: | none | strict | content | [ size || layout || paint ] |
| Initial: | none |
| Applies to: | 见 下文 |
| Inherited: | 否 |
| Percentages: | 不适用 |
| Computed value: | 关键字 none 或 一个或多个 size, layout, paint |
| Canonical order: | 按语法 |
| Animation type: | 不可动画化 |
用户代理预计需在所有媒介上支持此属性,包括非视觉媒介。
contain 属性允许作者指出一个元素及其内容在尽可能大的范围内与文档树的其余部分是 独立的。这使用户代理在正确使用 contain 时能够利用更强的优化,并使作者确信页面不会因无意更改而意外进入较慢的代码路径。
- none
- 此值表示该属性无任何效果。元素按正常方式呈现,不应用任何包含效果。
- strict
- 此值计算为 size layout paint,因此为元素开启所有形式的 包含。
- content
-
此值计算为 layout paint,因此为元素开启除 大小包含 之外的所有形式的 包含。
注: contain: content 在广泛应用时相对“安全”;其实践中的影响较小,大多数内容不会触及其限制。然而,由于它不应用 大小包含,元素仍然可以响应其内容的大小,这可能导致布局失效向上冒泡到比预期更高的树层。尽可能使用 contain: strict,以获得尽可能多的包含效果。
- size
- 此值为元素开启 大小包含。这确保可以在不检查其后代的情况下布置 包含框。
- layout
- 此值为元素开启 布局包含。这确保 包含框 在布局目的上是 完全不透明的;外部不能影响其内部布局,反之亦然。
- paint
- 此值为元素开启 绘制包含。这确保 包含框 的后代不会在其边界之外显示,因此如果某元素在屏幕外或以其他方式不可见,其后代也保证不可见。
此属性通常适用于所有元素(包括 CSS 伪元素 4 § 4.1
生成内容伪元素:::before 和 ::after),尽管某些类型的包含对某些元素无效,如 § 3 包含类型
中所述。此外,对于 [SVG2],contain 属性仅适用于具有关联 CSS 布局盒的
svg
元素。
例如,假设某微帖社交网络具有如下标记:
< body >
< aside > ...</ aside >
< section >
< h2 > Messages</ h2 >
< article >
Lol, check out this dog: images.example.com/jsK3jkl
</ article >
< article >
I had a ham sandwich today. #goodtimes
</ article >
< article >
I have political opinions that you need to hear!
</ article >
…
</ section >
</ body >
站点上可能显示 许多 消息,但每条消息都是独立的,不会影响站点上的其他内容。因此,每条消息都可以使用 contain: content 来向用户代理传达这一点,从而使其能够优化页面并为屏幕外的消息跳过大量计算。如果每条消息的大小事先已知,则可以使用 contain: strict 来传达更多限制。
此外,当 used value 的 contain 属性在 HTML 的
html
或
body
元素上不是 none 时,从
body
元素到初始包含块、视口或 画布背景 的属性传播将被禁用。值得注意的是,这会影响:
-
writing-mode、direction 和 text-orientation(参见 CSS Writing Modes 3 § 8 主写作模式)
-
overflow 及其简写属性(参见 CSS Overflow 3 § 3.3 溢出视口传播)
-
background 及其简写属性(参见 CSS Backgrounds 3 § 2.11.2 画布背景与 HTML <body> 元素)
注: 对于直接设置在
html
元素上的属性,传播到初始包含块、视口或 画布背景 不受影响。
3. 包含类型
元素可能受到几种不同的 包含,以不同方式限制其后代对页面其余部分的影响。包含 使用户代理能够进行更强大的优化,并帮助作者将页面构造成功能单元,因为它限制了某个更改对文档造成影响的范围。
引入新属性或机制的规范作者需要考虑各种包含类型是否以及如何影响它们所引入的内容,并在其规范中包含此处未描述的任何影响。
3.1. 大小包含
为元素提供 大小包含 会使其 主框 成为一个 大小包含框,并具有以下效果:
-
固有尺寸 的确定将如同元素没有内容一样确定 大小包含框 的尺寸,遵循与 按空内容进行尺寸计算 相同的逻辑。
注: 这会影响显式调用的 min-content 或 max-content 关键字,以及任何依赖这些测量的计算,例如将包含尺寸的项目放入的 网格轨道,或如果应用于包含框的父元素的 fit-content 尺寸。
-
布置 大小包含框 及其内容在概念上分为两个阶段:
- 按空内容进行尺寸计算
-
used 的 width 和 height 的确定是如同对该 包含框 执行正常布局,除了将其视为没有内容——即使是通过伪元素如 ::before、::after 或 ::marker 也不视为有内容。
替换元素 必须被视为具有自然宽度和高度为 0 且没有 自然宽高比。
注: 大小包含仅抑制 自然宽高比,因此像 aspect-ratio 这类直接影响 首选宽高比 的属性仍然会被遵守。
对 大小包含框 的所有 CSS 属性会像正常执行布局时那样被考虑在内。其他规范可能会做出特定的豁免。
注: 即便元素的 尺寸属性 指定了固有尺寸,这并不一定使元素变为零尺寸:设置在元素本身的属性仍会被考虑,这可能导致它更大。
- 在位置中进行布局
-
包含框 的内容(包括任何伪元素)必须在现在固定尺寸的 包含框 内正常地进行布局。
-
大小包含框 是 单片的(参见 CSS 分页 3 § 4.1 可能的断点)。
img{ width : 100 px ; aspect-ratio : 1 /1 ; contain : size; } < img src = "https://www.example.com/300x100.jpg" >
如果未声明 aspect-ratio 属性,图像将为 100px × 0px,因为其 自然宽高比 被抑制,其 自然高度 被视为 0。
但是,如果满足以下任一条件,为元素提供 大小包含 将不会产生效果:
-
如果该元素不生成 主框(例如 display: contents 或 display: none 的情况)
-
如果其 内部 display 类型 为 table
注: 内部表格框(不包括表格标题)被排除在外,因为表格布局算法不允许框小于其流内内容。将表格单元按空内容进行尺寸计算然后再在不改变尺寸的情况下布局其内容在实际上是未定义的操作。手动将 width 或 height 属性设置为 0 也不能使其小于其内容。这个问题不适用于表格标题,表格标题完全能够拥有独立于其内容的固定大小。
3.1.1. 可能的大小包含优化
本节为非规范性内容。
单独使用时,尺寸包含并不能带来太多优化机会。 它自身的主要好处是,想要根据包含盒尺寸来布局其内容的工具 (比如实现“容器查询”概念的 JS 库), 可以放心操作,无需担心“无限循环”—— 即当子元素的尺寸响应于包含盒的尺寸时,导致包含盒本身的尺寸也随之改变, 这可能进一步引发更多子元素尺寸的变化, 从而可能继续导致包含盒尺寸的变化, 如此往复,循环不止。
不过,当与 布局包含 配合使用时, 可以启用的可能优化包括(但不限于):
-
当包含框的某个后代的样式或内容发生变化时,计算 DOM 树中哪些部分被“弄脏”且可能需要重新布局可以在该 包含框 处停止。
-
在页面布局时,如果 包含框 在屏幕外或被遮挡,其内容的布局(即“在位置中进行布局”) 可以被延迟或以较低优先级执行。
3.2. 布局包含
为元素提供 布局包含 会使其 主框 成为一个 布局包含框,并具有以下效果:
-
如果某个 分片容器 所在的 分片上下文 有至少一个分片容器具有 布局包含, 或者如果某个分片上下文的至少一个分片容器是某个具有布局包含的元素的后代 并且 同一分片上下文的至少一个后续分片容器不是该具有布局包含元素的后代, 则第一个既是分片容器本身或是分片容器祖先的 布局包含框 必须“困住”剩余的分片流:分片 不得越过该 布局包含 边界继续, 并且位于第一个布局包含边界内的最后一个分片容器被视为其所在分片上下文的最后一个分片容器。
如果同一分片上下文中后续的分片容器仅在分片流中仍有内容时才会生成,则这些分片容器不会被生成。 如果它们无论如何都会存在,则它们仍属于该 分片上下文, 但不会从该 分片流 接收任何内容。
注: 在撰写本文时,没有稳定规范受此点影响。 只有那些可能使分片上下文的某些(但不是全部)分片容器可被布局包含(或成为布局包含元素的后代)的规范才会受到关注。 这既不是 [CSS-PAGE-3])也不是 [CSS-MULTICOL-1] 的情况。 尽管如此,该要求仍然被包含,因为已经考虑过若干机制会使这种情况成为可能(例如:[CSS-REGIONS-1]、::nth-fragment()、针对多栏的单独列的假想选择器等), 如果这些机制不遵守此规则,则布局包含旨在提供的保证将无法实现。[CSS-REGIONS-1] 中有关于布局包含如何影响 regions 的详细说明。
< article > Lorem ipsum…</ article > < div id = a ></ div > < aside > < div id = b ></ div > < div id = c ></ div > </ aside > < aside > < div id = d ></ div > < div id = e ></ div > </ aside > < div id = f ></ div > article{ flow-into : foo;} #a, #b, #c, #d, #e, #f{ flow-from : foo;} aside{ contain : layout} 在这个 [CSS-REGIONS-1] 示例中, 内容可以从
#a流到#b, 从#b流到#c。 然而因为#c是第一个 布局包含框 中的最后一个分片容器, 它会困住剩余的内容,#d、#e或#f将不会接收到内容。 -
强制分页 可以出现在 布局包含框 内,但不会像在 CSS Fragmentation 3 § 3.1 分盒之间的断点:break-before 和 break-after 属性 中所述那样向父级传播。
注: 这引入了以前不存在的可能性:强制分页 可能发生在一个框与其包含块之间(参见 CSS Fragmentation 3 § 4.1 可能的断点)。
-
就 vertical-align 属性而言, 或任何其他需要将 布局包含框 的基线位置与它的后代以外的东西相关联的属性, 该 包含框 被视为没有基线。
但是,如果满足下列任一情况,则为元素提供 布局包含 不会产生效果:
-
如果该元素不生成 主框(例如在 display: contents 或 display: none 的情况下)。
-
如果其 主框 是除 table-cell 之外的内部表格框(internal table box)。
-
如果其 主框 是内部注记框(internal ruby box)或非原子的行内级框(inline-level box)。
3.2.1. 可能的布局包含优化
本节为非规范性内容。
由 布局包含 启用的可能优化包括(但不限于):
-
在页面布局时,独立的 包含框 的内容可以并行进行布局,因为它们保证互不影响。
-
在页面布局时,如果 包含框 在屏幕外或被遮挡,且屏幕可见部分的布局不依赖于该 包含框 的尺寸(例如该包含框接近块容器的末尾,而你正在查看块容器的开头), 则可以延迟或以较低优先级对该 包含框 的内容进行布局。
(当与 大小包含 配合使用时,这种优化可以更自由地应用。)
3.3. 绘制包含
为元素提供 绘制包含 会使其 主框 成为一个 绘制包含框 并具有以下效果:
-
元素的内容,包括任何 墨迹 或 可滚动溢出,必须被裁剪到 填充边缘 上的 绘制包含框,并考虑到 拐角裁剪。这不包括创建任何访问或指示被裁剪内容存在的机制;也不阻止通过其他属性(例如 overflow、resize 或 text-overflow)创建任何此类机制。
注: 本规范的下一版 [CSS-CONTAIN-2] 将把此效果细化为应用于 溢出裁剪边缘,而不是 填充边缘,以便考虑新的 overflow-clip-margin 属性。对于不支持 overflow-clip-margin 的实现,该效果相同。
注: 本段所述行为等同于在使用值阶段将 overflow-x: visible 改为 overflow-x: clip,并将 overflow-y: visible 改为 overflow-y: clip,同时保持 overflow-x 和 overflow-y 的其他值不变。
但是,如果满足下列任一情况,则为元素提供 绘制包含 不会产生效果:
-
如果该元素不生成 主框(例如在 display: contents 或 display: none 的情况下)。
-
如果其 主框 是除 table-cell 之外的内部表格框(internal table box)。
-
如果其 主框 是内部注记框(internal ruby box)或非原子的行内级框(inline-level box)。
3.3.1. 可能的绘制包含优化
本节为非规范性内容。
由 绘制包含 启用的可能优化包括(但不限于):
-
如果 包含框 在屏幕外或被遮挡,用户代理通常可以跳过尝试绘制其内容,因为这些内容也保证在屏幕外或被遮挡。
注: 某些绘制效果(例如来自 [FILTER-EFFECTS-1] 的 blur() 过滤器)具有非本地效果。用户代理需要跟踪这些效果,因为当其后代发生变化时,即使这些后代具有 绘制包含 并且本可以被跳过,用户代理仍可能需要重新绘制应用此类滤镜的元素的某些部分。
-
除非通过诸如 overflow、resize 或 text-overflow 等单独机制使被裁剪内容可访问,用户代理可以仅为该框精确保留与框尺寸相等的“画布”空间。(在类似的可滚动场景中,例如 overflow: hidden,有可能滚动到当前被裁剪的内容,因此用户代理通常会预测性地多绘制一些内容,以便在滚动发生时立即有内容可见,而不是延后一帧。)
-
由于这些框被保证为堆叠上下文,滚动的元素可以被绘制到单个 GPU 图层中。
4. 隐私注意事项
本规范中的特性目前没有已知的隐私影响。
5. 安全注意事项
本规范中的特性目前没有已知的安全影响。
像任何其他 CSS 规范一样,它影响文档的渲染,但并未引入任何此前通过其他 CSS 模块不可用且不是格式化文档行为固有的误导性呈现内容的特殊能力。
附录 A. 更改
本附录为 参考性 内容。
来自 2022年10月25日 推荐版 的更改
三个建议更正已正式并入规范性文本:
- 建议更正 1:
- 对 contain 属性的计算值确定方式进行了小幅调整:快捷值(strict 和 content)不再计算为它们自身,而是计算为相应的关键字。鉴于效果相同,这允许实现不必存储实现所使用的精确语法。此外,受最短序列化原则的影响,这使得通过序列化无法观察到这一不重要的差异。
- 建议更正 2:
- 对大小包含的描述存在一些歧义,导致实现者对某些情况下的预期行为有疑问。该描述已被替换为更精确的描述,以在不改变预期行为的情况下澄清含义。
- 建议更正 3:
- CSS 工作组曾忘记考虑包含对 HTML 的
html和body元素的影响,特别是考虑到出于遗留原因,某些属性可以从body元素向外传播。所添加的文本对这一疏忽进行了处理。
一份 实现报告 详细说明了它们在多个引擎中的实现情况。
早期更改
有关本规范早期更改的详细信息可见于 其先前出版物的“更改”部分。