1. 简介
高效渲染网站依赖于用户代理能够检测页面的哪些部分正在显示,哪些部分可能会影响当前显示的部分,以及哪些部分可以忽略。
有各种启发式方法可以用来判断某个给定的子树在某种程度上是否独立于页面的其他部分,但它们很脆弱,因此对页面的无害更改可能会无意中使其无法通过此类启发式测试,导致渲染进入慢速代码路径。 还有许多事情值得隔离,但很难或不可能以启发式方式检测到。
为缓解这些问题并允许从页面的其他部分强烈且可预测地隔离子树,本规范定义了一个 contain 属性。
为了进一步优化屏幕外内容,本规范还定义了一个 content-visibility 属性, 使用户代理在不需要时能够完全跳过元素的布局和绘制。
1.1. 模块交互
本文档定义了早期规范中不存在的新特性。此外,它旨在一旦稳定后替换并取代 [CSS-CONTAIN-1]。
1.2. 值定义
本规范遵循 CSS 属性定义约定,来自 [CSS2],并使用 值定义语法,来自 [CSS-VALUES-3]。 未在本规范中定义的值类型在 CSS Values & Units [CSS-VALUES-3] 中定义。 与其他 CSS 模块的结合可能会扩展这些值类型的定义。
除了在定义中列出的特定于属性的值外,本规范中定义的所有属性还接受 CSS 宽泛关键字 作为其属性值。 为了可读性,它们没有被明确重复。
2. 强包含: contain 属性
| 名称: | contain |
|---|---|
| 值: | none | strict | content | [ size || layout || style || paint ] |
| 初始值: | none |
| 适用于: | 参见 下文 |
| 继承: | 否 |
| 百分比: | 不适用 |
| 计算值: | 关键字 none 或 size, layout, paint 中的一个或多个 |
| 规范顺序: | 按语法顺序 |
| 动画类型: | 不可动画 |
用户代理应支持在所有媒体(包括非视觉媒体)上使用此属性。
contain 属性允许作者指示一个元素及其内容在尽可能大的程度上与文档树的其余部分独立。 这使得用户代理在正确使用 contain 时能够在渲染页面时利用更强的优化,并使作者可以确信其页面不会因无害的更改而意外地进入慢速代码路径。
- none
- 此值表示该属性没有效果。 元素正常渲染,没有应用任何包含效果。
- strict
- 此值计算为 size layout paint style,因此为该元素开启所有形式的 包含。
- content
-
此值计算为 layout paint style,因此为该元素开启所有形式的 包含,除了 尺寸包含。
注意: contain: content 在广泛应用时是相对“安全”的; 其效果在实际中相对较小,并且大多数内容不会触犯其限制。 然而,由于它不适用于 尺寸包含,因此元素仍然可以响应其内容的大小,这可能导致布局失效传播到树中比预期更远的地方。 在可能的情况下,使用 contain: strict 以获得尽可能多的包含。
- size
- 该值为元素开启 尺寸包含。 这确保了 包含盒 可以布局而不需要检查其后代。
- layout
- 此值为元素开启 布局包含。 这确保了 包含盒 在布局时完全不透明; 外部的任何东西都不能影响其内部布局,反之亦然。
- style
- 此值为元素开启 样式包含。 这确保了对于可能对不仅仅是元素及其后代产生影响的属性,这些影响不会超出元素。
- 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 以传达进一步的限制。
此外,当任何 包含 激活在 HTML
html
或
body
元素上时, 从
body
元素向 初始包含块、视口或 画布背景 的属性传播将被禁用。 尤其是,这会影响:
-
writing-mode、direction 和 text-orientation(参见 CSS Writing Modes 3 § 8 主要书写模式)
-
overflow 及其分支(参见 CSS Overflow 3 § 3.5 溢出视口传播)
-
background 及其分支(参见 CSS Backgrounds 3 § 2.11.2 画布背景与HTML <body> 元素)
注意: 设置在
html
元素本身上的属性不会影响其向 初始包含块、视口或 画布背景 的传播。
注意: 除了 contain 之外, 还有几种属性可以为元素开启各种 包含。 这些属性不会影响 contain 的值; 例如,一个元素可以具有 contain: none,但仍然可以通过 content-visibility 为其开启 布局包含。
3. 容器类型
一个元素可能受到几种不同类型的容器的限制,从而以不同方式限制其后代对页面其余部分的影响。容器使用户代理能够进行更强大的优化,并帮助作者将页面组合成功能单元,因为它限制了特定更改对文档的影响范围。
规范作者在引入新属性或机制时需要考虑各种容器类型是否以及如何影响他们所引入的内容,并在规范中包括此处未描述的任何影响。
3.1. 尺寸容器
为一个元素赋予尺寸容器会使其主框成为一个尺寸容器框,并具有以下效果:
-
固有尺寸会按照元素没有内容的情况来确定尺寸遏制盒的固有尺寸, 遵循与按空内容进行尺寸计算时相同的逻辑。
注: 这会影响对 min-content 或 max-content 关键字的显式调用, 以及任何依赖这些测量值的计算, 例如对放置了尺寸遏制项目的网格 轨道进行尺寸计算, 或者对遏制盒的父元素进行适合内容尺寸计算。
-
对尺寸遏制盒及其内容进行布局,在概念上分为 两个阶段:
- 按空内容进行 尺寸计算
-
遏制盒的使用 width 和 height 按照对该盒执行正常布局的方式确定,
不同之处在于,它被视为没有任何内容——
甚至不包括通过诸如 ::before、::after 或 ::marker 这样的伪元素产生的内容。 替换元素必须被视为具有 0 的自然宽度和高度, 并且没有自然宽高比。
注: 尺寸遏制仅抑制自然宽高比, 因此像 aspect-ratio 这样直接影响该首选宽高比的属性 仍会生效。
尺寸遏制盒的所有 CSS 属性都会像 正常执行布局时一样被考虑。 其他规范可能会规定特定的例外情况。
注: 即使元素的尺寸属性指定了固有尺寸, 这也不一定会使元素的尺寸变为零: 元素自身设置的属性 仍会被考虑, 这可能会使其变得更大。
- 原位 布局
- 然后必须将遏制盒的内容 (包括任何伪元素) 正常布局到此时尺寸已固定的遏制盒中。
img{ width : 100 px ; aspect-ratio : 1 /1 ; contain : size; } < img src = "https://www.example.com/300x100.jpg" >
然而,当满足以下任意条件时,为一个元素赋予尺寸容器将无效:
注意:内部表格框,不包括表格标题栏,被排除在外,因为表格布局算法不允许框比其流入内容更小。将表格单元格按空布局并在内部布局其内容而不改变尺寸,实际上是未定义的操作。手动将宽度或高度属性设置为0不能使其比内容更小。这一问题不适用于表格标题栏,它们完全可以具有独立于其内容的固定大小。
3.1.1. 可能的尺寸容器优化
本节为非规范性内容。
单独来看,尺寸 遏制并没有提供太多优化机会。 它自身的主要好处是,那些希望根据遏制盒的尺寸 来布局遏制盒内容的工具 (例如实现“容器查询”概念的 JS 库) 可以这样做而不必担心出现“无限循环”, 即让子元素的尺寸响应遏制 盒的尺寸会导致遏制盒的尺寸也发生变化, 从而可能触发子元素调整自身尺寸方式的进一步变化, 并因此可能导致遏制盒的尺寸发生更多变化, 如此无限循环。
不过,当与布局 遏制配合使用时, 可以启用的优化包括(但不限于):
-
当遏制盒的后代的样式或内容发生更改时, 在计算 DOM 树的哪些部分被“标记为脏”并可能需要重新布局时, 可以在遏制盒处停止。
3.2. 布局容器
为一个元素赋予布局容器会使其主框成为一个布局容器框,并具有以下效果:
-
如果一个分片上下文中至少有一个分片容器具有布局遏制, 或者一个分片上下文中至少有一个分片容器是布局 遏制盒的后代,并且同一分片上下文中至少有一个后续分片容器不是同一个具有布局遏制的元素的后代, 那么第一个布局遏制盒,其本身 要么是一个分片容器, 要么是一个分片容器的祖先, 必须“截留”分片流的剩余部分:分片不得越过布局遏制边界继续进行, 并且第一个布局遏制边界内的最后一个分片容器 会被视为其分片上下文中的最后一个分片 容器。
如果分片上下文中的后续分片容器仅在分片流中还有更多 内容剩余时才会生成, 那么它们不会被生成。 如果无论如何它们都会存在, 则它们仍然是分片上下文的一部分, 但不会从分片流接收任何内容。
注: 在撰写本文时,没有稳定的规范 受到此项影响。 只有那些允许分片上下文中的某些(但不是全部)分片容器 具有布局遏制(或作为具有布局遏制的元素的后代)的规范 才与此有关。 [CSS-PAGE-3] 和 [CSS-MULTICOL-1] 都不存在这种情况。 尽管如此,仍包含此要求,因为 已经考虑了几种可能使这种情况成为可能的机制 (例如:[CSS-REGIONS-1]、::nth-fragment()、一个假想的用于 多栏中各个栏的选择器……), 如果这些机制不遵守此规则,布局遏制旨在提供的保证将无法实现。[CSS-REGIONS-1] 详细说明了布局 遏制如何影响 区域。
< 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。 -
如果 overflow 属性的计算值 是 visible 或 clip,或者二者的组合, 则任何溢出都必须被视为墨水 溢出。
-
强制分断允许出现在布局遏制盒内部, 但不会像CSS 分片 3 § 3.1 盒之间的分断:break-before 和 break-after 属性中所述的其他情况那样传播到父级。
注: 这引入了此前不存在的一种可能性, 即强制分断可能发生在盒与其容器之间(参见CSS 分片 3 § 4.1 可能的分断点)。
-
对于 vertical-align 属性, 或任何其他其效果需要将布局遏制盒的基线位置 与其后代以外的某个对象相关联的属性而言, 遏制盒被视为没有 基线。
然而,当满足以下任意条件时,为一个元素赋予布局容器将无效:
3.2.1. 可能的布局容器优化
本节为非规范性内容。
布局容器可能启用的优化包括(但不限于):
-
在布局页面时,单独的容器框的内容可以并行布局,因为它们保证不会相互影响。
-
在布局页面时,如果容器框不在屏幕上或被遮挡,并且屏幕上可见部分的布局不依赖于容器框的大小(例如,如果容器框接近块级容器的末尾,而你正在查看块级容器的开头),则容器框内容的布局可以延迟或以较低优先级完成。
(当与尺寸容器配合使用时,此优化可以更广泛地应用。)
3.3. 样式容器
为一个元素赋予样式容器会产生以下效果:
-
counter-increment和counter-set属性必须限定在元素的子树内,并创建一个新的计数器。
-
content属性的open-quote、close-quote、no-open-quote和no-close-quote的效果必须限定在元素的子树内。
注意: 这意味着子树中的引用嵌套深度保持不变,并从其上下文通常暗示的值开始,但这些值在子树内对引用嵌套深度的更改不会影响子树外的引用嵌套深度。
注意: [CSS-REGIONS-1]对样式容器如何影响区域有规范性要求。
-
如果限定在元素上,它必须在评估属性效果时,表现得好像限定元素是文档的根:限定元素外的属性使用对限定元素上或限定元素内的属性使用没有影响,反之亦然。
注意: “限定在元素上”目前未使用。它被定义为供未来规范使用的扩展点。
-
如果限定在子树内,它的效果相同,只不过限定元素本身被视为树外,与文档的其他部分一样,属性对该元素的效果不受限定影响。在考虑限定属性对子树内元素的影响时,子树底部的元素被视为文档的根。
1 1.2:
< div ></ div >
div {
contain : style;
counter-increment : n;
}
div::before, div::after {
content : counters ( n, '.' ) " " ;
}
div::after {
counter-increment : n 2 ;
}
3.3.1. 可能的样式容器优化
本节为非规范性内容。
样式容器可能启用的优化包括(但不限于):
-
当一个具有样式容器的元素的后代元素上的属性发生变化时,计算DOM树的哪些部分被“弄脏”并可能需要重新计算样式,可以在具有样式容器的元素处停止。
3.4. 绘制容器
为一个元素赋予绘制容器会使其主框成为一个绘制容器框,并具有以下效果:
-
元素的内容(包括任何墨水溢出或可滚动溢出)必须剪裁到溢出剪裁边缘的绘制容器框内,考虑[[css-backgrounds-3#corner clipping|角剪裁]]。这不包括创建任何机制来访问或指示被剪裁内容的存在;也不妨碍通过其他属性创建任何此类机制,例如溢出、调整大小或文本溢出。
注意: 此剪裁形状尊重overflow-clip-margin,允许具有绘制容器的元素仍然稍微超出其正常边界。
注意: 本段描述的行为相当于在使用值时将overflow-x: visible更改为overflow-x: clip,并将overflow-y: visible更改为overflow-y: clip,而其他overflow-x和overflow-y的值保持不变。
然而,当满足以下任意条件时,为一个元素赋予绘制容器将无效:
3.4.1. 可能的绘制容器优化
本节为非规范性内容。
绘制容器可能启用的优化包括(但不限于):
-
如果容器框不在屏幕上或被遮挡,UA通常可以跳过尝试绘制其内容,因为它们也保证处于屏幕外/被遮挡状态。
注意: 某 些绘制效果(如blur()滤镜)具有非局部效果。用户代理需要跟踪这些效果,因为当其后代发生变化时,即使它们具有绘制容器且本可以跳过,也可能需要重新绘制带有此类滤镜的元素的部分内容。
-
除非通过其他机制(如溢出、调整大小或文本溢出属性)使剪裁内容可访问,UA可以为该框保留与框大小完全一致的“画布”空间。(在类似的可滚动情况下,如overflow: hidden,可以滚动到当前被剪裁的内容,所以UA通常会预见性地多绘制一些,以便在滚动发生时立即显示内容,而不是在稍后的一帧中显示。)
-
因为它们保证是堆叠上下文,滚动元素可以绘制到单个GPU图层中。
4. 完全抑制元素的内容:content-visibility属性
| 名称: | content-visibility |
|---|---|
| 值: | visible | auto | hidden |
| 初始值: | visible |
| 适用于: | 可以应用布局容器的元素 |
| 继承: | 否 |
| 百分比: | 不适用 |
| 计算值: | 按指定值 |
| 规范顺序: | 按语法 |
| 动画类型: | 不可动画 |
content-visibility属性控制元素是否完全渲染其内容,同时强制实施一系列容器,允许用户代理在需要之前省略大量布局和渲染工作。该属性具有以下值:
- visible
-
无效。元素的内容按常规布局和渲染。
- hidden
-
元素跳过其内容。
跳过的内容必须对用户代理功能(例如页面查找、Tab顺序导航等)不可访问,也不可选中或聚焦。
注意: 这类似于将内容设置为display: none。
- auto
-
与不同,跳过的内容必须仍然可以被用户代理功能正常访问,例如页面查找、Tab顺序导航等,并且必须能够正常聚焦和选择。
用户代理应尽可能避免对跳过的内容进行布局/渲染工作;重度容器和使内容不可见且不可触摸的组合允许进行重度优化。如果某个时刻进行了渲染工作,用户代理应保留先前计算的布局状态,以便稍后可以快速显示跳过的内容。
-
布局容器确保用户代理能够在跳过的子树中省略布局工作,因为这种布局的结果不会影响容器元素外的元素。
-
样式容器确保在跳过的子树中不需要处理计数器,因为它们不会影响容器元素外的计数器。
-
绘制容器确保绘制内容的墨水溢出被剪裁;这反过来意味着用户代理可以可靠地确定元素的可见部分何时接近视口(并且,对于content-visibility: auto,开始绘制它)。
-
尺寸容器确保用户代理能够在跳过的子树中省略布局,因为这种布局的结果不会影响容器元素的大小。
请注意,在content-visibility: auto的情况下,即使元素未被跳过,布局容器、样式容器和绘制容器仍然存在。这是为了防止由于元素进入和退出跳过状态而导致的容器更改所引起的布局变化。
4.1. 使用content-visibility: hidden
本节为非规范性内容。
content-visibility: hidden对元素施加了强大的限制,因此应谨慎使用。它还启用了一些非常有用的场景,通常改进了现有技术,以下是其中一些。
-
如果页面需要对不会被渲染的元素或文本进行一些测量,通常会将要测量的内容定位到屏幕外,使用类似于position: absolute; left: -100000px;,然后调用类似
getBoundingClientRect()的API。不幸的是,即使页面从未打算显示这些内容,用户代理仍然必须为这些内容执行完整的样式、布局和渲染工作,以防它影响屏幕上的显示。作者也不能保证内容不会意外出现在屏幕上;即使是非常负的left值(如上所述)可能也不足以确保这一点,具体取决于内容。
将这些内容包装在一个content-visibility: hidden容器中解决了所有这些问题。如果包装器没有边框、背景等,那么它和它的跳过的内容保证永远不会渲染到屏幕上,无论它们有多大。因为内容被跳过,用户代理也可以避免对其进行样式处理或布局,直到脚本最终需要时。
-
一个“单页应用程序”通常由几个独立的窗格或“视图”组成,其中只有一个同时显示。
如果作者想要避免为非活动视图支付样式/布局/渲染等成本,他们可以将其完全从文档中移除,或者至少对其应用display:none。不幸的是,这意味着当视图确实需要显示时,所有样式/布局/渲染等工作都需要一次性完成,可能会导致视图实际显示之前的明显延迟。
或者,可以将视图定位到屏幕外。这意味着当需要使用时,它将立即准备好,但它会一直消耗样式/布局/渲染的成本,这可能是显著的,特别是如果有许多非活动视图。非活动视图也可能仍然会出现在辅助工具中,混淆使用屏幕阅读器的用户、使用Ctrl-F进行页面查找的人等。
content-visibility: hidden改进了这两种选项。因为内容被跳过,当它们不活动时,用户代理不会花费时间在它们上。它们也不会对屏幕阅读器、页面查找和其他工具可见。并且因为用户代理应尽可能保留以前的样式/布局工作,如果视图以前已经显示过,重新渲染它可能会非常快。
-
如果作者想让一个元素“不可见”,但仍然在页面中显示以用于布局目的,一个选项是visibility: hidden。然而,visibility: hidden元素的后代可以设置visibility: visible并重新显示,这并不总是直观或预期的。
content-visibility: hidden执行非常类似的功能,但后代无法“关闭”它并开始显示;它们保持“隐藏”,直到祖先关闭它。
因为content-visibility: hidden还将许多容器值应用于容器,它并不总是像visibility: hidden那样可用,但当其限制可以接受时,它可以是一种更可靠、更一致的方式来隐藏元素的内容。
4.2. 使用content-visibility: auto
本节为非规范性内容。
content-visibility: auto比更复杂;它不是类似于display: none,而是随着元素的内容变得与用户相关时,自适应地隐藏/显示元素的内容。它也不会将其跳过的内容从用户代理中隐藏,因此屏幕阅读器、页面查找和其他工具仍然可以与其交互。
最好将其视为对容器的升级:如果作者有大量内容需要显示,并且这些内容通常会在屏幕外(例如一个可滚动的长列表),并且该内容可以接受重度容器,他们应该考虑使用content-visibility: auto一次性应用所有的容器。这也强烈暗示用户代理可以跳过内容的工作(可能会导致内容进入屏幕时出现小延迟),因为文档中有大量内容,其中大部分内容无论如何都不会被看到。
注意:因此,content-visibility: auto可以替代复杂的“虚拟列表”技术,至少在许多情况下可以如此。
由于content-visibility: auto只有在元素的内容对用户不相关时才会导致元素跳过其内容,因此最好在合理细粒度下使用。
相反,content-visibility应该应用于单个推文,允许它们在离开屏幕时被跳过。
由于content-visibility: auto在元素跳过其内容时会施加尺寸容器,如果元素依赖于其内容来确定其大小,页面布局(或至少,滚动条位置)可能会在元素离开屏幕并开始跳过时“跳动”。
-
将元素设置为固定大小
-
仔细安排布局(例如Grid)以在不依赖内容的情况下确定元素大小
-
使用contain-intrinsic-size来设置元素大小的估计值
-
使用contain-intrinsic-size: auto自动从上次渲染时对元素的确切大小进行“快照”,在它被跳过之前(并提供在其渲染之前要使用的大小估计,以便可以对其大小进行快照)
例如,在Twitter上,平均推文约为200px高,因此contain-intrinsic-size: auto 500px 200px将确保滚动条滑块大致处于正确的大小和位置,即使前面的或后面的推文被跳过,同时仍然允许推文在屏幕上时根据其内容进行调整。只要推文至少被查看过一次(并且在它们跳过时没有改变大小),它们的大小将准确无误地在跳过时被保留,因此滚动条滑块也将如此;只有新加载的推文(例如当你向下滚动时在时间线顶部加载的推文)将不得不依赖200px的高度估计。
4.3. 检测content-visibility: auto状态变化:contentvisibilityautostatechanged事件
当渲染状态发生变化并且元素开始或停止与用户相关时,具有content-visibility:
auto样式的元素上会触发contentvisibilityautostatechanged事件。
此事件通过在状态变化发生时发布任务来调度。
[Exposed =Window ]interface :ContentVisibilityAutoStateChangedEvent Event {(constructor DOMString ,type optional ContentVisibilityAutoStateChangedEventInit = {});eventInitDict readonly attribute boolean skipped ; };dictionary :ContentVisibilityAutoStateChangedEventInit EventInit {boolean skipped =false ; };
ContentVisibilityAutoStateChangedEvent属性描述:
请注意,即使在content-visibility: auto子树中的元素跳过其内容,它们仍然在语义上与元素相关。这意味着使用此信号无限期地跳过被跳过子树中的DOM更新是不合适的。相反,它应该用于降低更新的优先级,但确保内容在语义上保持相关并且合理地保持最新。这对于即使在祖先设置为跳过其内容时仍然使用这些内容的辅助技术尤为重要。
4.4. 限制和澄清
-
从
IntersectionObserver的角度来看, 元素的被跳过的 内容 永远不会与交叉根相交。 即使根元素和目标元素 都位于被跳过的内容中,也是如此。 -
从
ResizeObserver的角度来看, 元素的被跳过的 内容 永远不会改变其大小。 如果这些元素随后变为不再被跳过, 并且新大小与上次用于通知调整大小观察器的大小不同, 则会传递调整大小观察结果。 -
如果元素开始或停止跳过其内容, 此更改会在 渲染该更改效果的帧的 requestAnimationFrame 回调 运行之后发生。 具体来说,此类更改将在处理模型的更新渲染步骤的第 13 步和第 14 步之间生效 (即“运行动画帧回调” 和“运行更新交叉观察步骤”之间)。
确定元素与视口的交叉情况 可以使用 IntersectionObserver 的内部版本来完成。 但是,由于由此产生的观察结果会在 更新渲染的第 14 步分派, 因此对跳过(进而是绘制)状态的任何更改 直到下一帧处理时才会对用户可见。 因此,更新跳过状态, 包括遏制调整, 也会推迟到该帧进行。 这可确保脚本在这两个事件之间访问, 例如, 元素的遏制值 (内部交叉观察和跳过状态 更新) 时,将获取与当前绘制状态一致的值, 并且不会导致任何强制布局。 -
对于 content-visibility: auto,初始可见性判定必须 与判定存在新的 content-visibility: auto 元素在同一帧中 发生。
当元素首次获得 content-visibility: auto 时,它可能位于屏幕上,也可能不在 屏幕上。对此状态的判定,进而 对该元素是否被跳过的判定,必须在 同一帧中发生。否则,就有可能在元素所在位置产生空白 内容,因为可见性检查和跳过状态 更新将被推迟到下一帧。 -
对于滚动操作, 例如
scrollIntoView(), 具有 content-visibility: auto 且正在跳过其 内容的元素,其大小和位置是在尺寸遏制仍然有效的情况下确定的。注: 一旦滚动到视图中, 元素将不再跳过其内容, 因此可能不再具有尺寸遏制; 如果这改变了元素的大小, 它在视口中的对齐可能不会完全符合请求。
如果某个元素对用户代理特性不可用 (例如,如果它由于具有 content-visibility: hidden 的祖先而被跳过), 那么滚动操作 完全不得滚动到该元素, 就像它没有布局盒一样。
-
如果具有 content-visibility: auto 且正在跳过其 内容的元素获得焦点 (或其内容获得焦点), 则它会在因获得焦点而滚动到视图中之前变得与用户相关(因而停止跳过其内容)。
注: 因此,与上一点不同, 元素的大小和在视口中的对齐将是正确的。 这与
focus()方法的步骤顺序一致。 -
如果
iframe跳过其 内容,或者属于某个元素的被跳过的 内容的一部分, 如果可能,用户代理应完全跳过 iframe 事件循环中的更新渲染步骤。 -
当元素被跳过时, 元素上的 CSS 过渡和动画不会更新:
-
即使新应用的样式会启动动画,也不会创建新的动画。
-
现有动画不会沿其时间线推进。
-
元素上正在运行的动画不会结束。
如果脚本查询一个被跳过元素的样式 (从而导致样式更改事件), 并且为了返回正确信息而需要知道动画或过渡的状态, 则会根据该样式更改 事件发生时的样式 对动画和过渡进行采样:
CSS 动画 2 § 4 动画事件和CSS 过渡 2 § 5 过渡事件定义了动画或过渡更新时 会创建哪些对象、 会触发哪些事件, 以及这些事件携带哪些数据。
当元素停止被跳过时, 会对动画和过渡进行采样, 随后它们会从该点开始照常沿各自的时间线继续推进。
注: 总体而言,这类似于 后台标签页重新回到前台时 过渡/动画的行为, 允许用户代理尽可能跳过不必要的动画工作, 同时又不会在动画重新变得相关时对其造成过多干扰。
-
-
当元素被跳过时, 它不得启动任何过渡, 即使样式更改事件影响了其计算样式。
当元素停止被跳过时, 它不得因与其不再被跳过相关联的样式更改事件 而启动任何过渡。
注: 这类似于元素从 display:none 切换为非 none 值——
即使在这种情况下样式 从技术上讲确实发生了变化 (从它们的初始值 变为层叠产生的“正确”值), 也不会启动任何过渡。 -
如果元素有一个具有 content-visibility: hidden 的祖先, 并且它被放置在顶层中, 则它不会生成任何盒, 就像它是 display: none 一样。
注: 因其他原因而被跳过的元素, 例如具有 content-visibility: auto 祖先的元素, 仍会照常生成盒, 因而可能变为不再被跳过。
4.5. 无障碍影响
如果用户代理暴露某种形式的“无障碍树”,类似于DOM树但专门用于无障碍用例,例如屏幕阅读器(从而提供与无障碍API相关的元素位置等),那么跳过的内容在content-visibility: hidden元素中也必须类似地在无障碍树中“跳过”(省略)(类似于display: none元素在文档的所有视图中被省略)。
跳过的内容在content-visibility: auto元素中不得暴露用户通过无障碍树与页面交互的事实,而不是通过视觉呈现在屏幕上。特别是,如果用户代理使用content-visibility: auto避免对屏幕上未显示的内容进行布局和绘制工作,那么它也必须避免对无障碍树中未显示的内容进行此类工作。如果这不可能(例如,如果用户代理在无障碍树中表示一个可聚焦元素需要知道其确切位置,因此需要对其及周围内容进行完整布局),那么用户代理必须完全省略无障碍树中的跳过的内容。
注意:此要求旨在保护使用无障碍工具的用户免于通过时间通道的观察被识别和分析;如果用户代理在视觉呈现时可以跳过大量工作,但在呈现给无障碍树时必须完成所有工作,那么作者可以通过观察布局操作的时间来判断用户如何与页面交互。
4.6. 示例
< style > . sv { content-visibility : auto ; min-height : 50 px ; } </ style > < div class = sv > ... some content goes here ...</ div >
.sv 元素的 content-visibility: auto 值允许用户代理管理元素是否被跳过。特别是当此元素接近视口时,用户代理将开始绘制元素。当元素移离视口时,它将停止绘制。此外,当元素被跳过时,用户代理应尽可能跳过渲染工作。
< style > . sv { content-visibility : hidden ; } </ style > < div class = sv > ... some content goes here ...</ div >
在此示例中,无论视口交集如何,元素都被跳过。这意味着唯一能让内容绘制出来的方法是通过脚本更新值以删除content-visibility或更改其值。同样,用户代理应尽可能跳过内容中的渲染工作。
跳过渲染的附加效果是用户代理可以保留内容的布局状态,因此将来删除content-visibility属性时,内容的渲染速度会比使用display: none或类似方式隐藏时更快。
< style > body { margin : 0 ; } . sv { content-visibility : hidden ; position : relative ; left : 10 px ; top : 20 px ; } # child { position : relative ; left : 1 px ; top : 2 px ; width : 100 px ; height : 200 px ; } </ style > < div id = target class = sv > < div id = child ></ div > ... some other content goes here ...</ div > < script > ... // This will force rendering work, including layout, // if the UA previously avoided it. target. firstElementChild. getBoundingClientRect(); ... </ script >
与上一个示例类似,元素被跳过。用户代理应尽可能避免渲染工作。然而,在此示例中,在某个时刻脚本访问了元素内容中的布局值。在这种情况下,用户代理无法避免渲染工作,并且必须处理任何先前跳过的渲染工作,以便向调用者返回正确的值。在此示例中,getBoundingClientRect()的结果是一个位置为
(11, 22) 且大小为 100x200 的矩形。
请注意,对同一布局值的重复调用不应导致任何额外的渲染工作,因为用户代理应保留最后更新的渲染状态。
还请注意,需要渲染工作的这种情况并不是唯一的。在某些其他情况下,用户代理可能也无法避免渲染工作。
5. 隐私考虑
本规范中的功能没有已知的隐私影响。
6. 安全考虑
本规范中的功能没有已知的安全影响。
像其他任何 CSS 规范一样,它影响文档的渲染,但不会引入任何特殊能力,以之前未通过其他 CSS 模块提供的方式,或者通过格式化文档行为本身误导性地呈现内容。
附录 A. 变更
本附录是说明性的。
自2020-12-16 工作草案以来的变更
-
定义动画和过渡如何作用于被跳过的元素。
-
移除“风险”标记中的样式包含部分。
-
在启用包含时,禁用从 HTML body 元素的传播。
-
澄清 scrollIntoView() 不会滚动到content-visibility:hidden元素的子元素。
-
定义具有content-visibility:hidden祖先的元素不会在顶层生成框。
-
定义在顶层使得元素与用户相关。
-
指出具有非本地效果的绘画效果可能会限制某些优化机会。
-
添加 ContentVisibilityAutoStateChanged 事件。
自2020-06-03 工作草案以来的变更
-
更改了 contain 属性计算值的确定方式
-
修复了有关 contain: content 的注释中的语法错误
-
更改术语:将 "containing box" 替换为 "containment box"(与对 Level 1 所做的相同 改进保持同步)
-
对尺寸遏制和绘制遏制进行了编辑性改进和澄清(与对 Level 1 所做的相同 改进保持同步)
-
明确指出尺寸遏制会抑制自然宽高比(与对 Level 1 所做的相同改进 保持同步)
-
将 content-visibility 的动画类型从离散更改为不可动画
-
在§ 4.4 限制和澄清中添加了对 content-visibility: auto 初始可见性判定时机的约束
自2019-11-11 工作草案以来的变更
-
添加了content-visibility属性。
自CSS 包含级别 1以来的变更
-
恢复了在第 1 级中被删除的样式包含。