CSS 包含模块第2级

W3C 工作草案,

更多关于本文件的信息
此版本:
https://www.w3.org/TR/2022/WD-css-contain-2-20220917/
最新发布的版本:
https://www.w3.org/TR/css-contain-2/
编辑草案:
https://drafts.csswg.org/css-contain-2/
之前的版本:
历史记录:
https://www.w3.org/standards/history/css-contain-2
测试套件:
https://test.csswg.org/harness/results/css-contain-1_dev/
https://wpt.fyi/results/css/css-contain/
反馈:
CSSWG 问题存储库
编辑:
Tab Atkins (Google)
Florian Rivoal (代表 Bloomberg)
(Google)
建议编辑此规范:
GitHub 编辑器

摘要

这个CSS模块描述了 contain 属性,该属性表明元素的子树与页面的其他部分是独立的。 当合理使用时,这可以使用户代理进行大幅度的优化。

CSS 是一种描述结构化文档(如HTML和XML)在屏幕、纸张等介质上呈现方式的语言。

本文档的状态

本节描述了本文档在发布时的状态。 当前W3C出版物的列表和此技术报告的最新修订版可以在 W3C技术报告索引 https://www.w3.org/TR/ 中找到。

本文档由 CSS工作组 作为 工作草案 发布,使用的是 推荐路径。 作为工作草案发布并不意味着 W3C 及其成员的认可。

这是一个草案文件,可能随时被更新、替换或由其他文件取代。 不宜将此文件引用为其他正在进行的工作。

请通过 在GitHub中提交问题(优选)来提供反馈, 在标题中包括规范代码“css-contain”,例如:“[css-contain] …评论摘要…”。 所有问题和评论都被 归档。 另外,也可以通过(已归档)公共邮件列表 www-style@w3.org 发送反馈。

本文档受 2021年11月2日W3C流程文件 管辖。

本文档由在 W3C专利政策 下运作的小组制作。 W3C维护了一个 公开的专利披露列表,该列表中列出了与小组交付物相关的任何专利披露; 该页面还包含了披露专利的说明。 知道自己所掌握的专利中包含 必要声明 的个人,必须根据 W3C专利政策第6节 披露信息。

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 元素。

contain 在页面上广泛使用时很有用, 特别是在页面包含大量彼此独立的“小部件”时。

例如,假设一个微帖子社交网络的标记类似于以下内容:

<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 元素向 初始包含块、视口或 画布背景 的属性传播将被禁用。 尤其是,这会影响:

注意: 设置在 html 元素本身上的属性不会影响其向 初始包含块、视口或 画布背景 的传播。

注意: 除了 contain 之外, 还有几种属性可以为元素开启各种 包含。 这些属性不会影响 contain 的值; 例如,一个元素可以具有 contain: none,但仍然可以通过 content-visibility 为其开启 布局包含。

3. 容器类型

一个元素可能受到几种不同类型的容器的限制,从而以不同方式限制其后代对页面其余部分的影响。容器使用户代理能够进行更强大的优化,并帮助作者将页面组合成功能单元,因为它限制了特定更改对文档的影响范围。

规范作者在引入新属性或机制时需要考虑各种容器类型是否以及如何影响他们所引入的内容,并在规范中包括此处未描述的任何影响。

3.1. 尺寸容器

为一个元素赋予尺寸容器会使其主框成为一个尺寸容器框,并具有以下效果:

  1. 固有尺寸会按照元素没有内容的情况来确定尺寸遏制盒的固有尺寸, 遵循与按空内容进行尺寸计算时相同的逻辑。

    注: 这会影响对 min-content 或 max-content 关键字的显式调用, 以及任何依赖这些测量值的计算, 例如对放置了尺寸遏制项目的网格 轨道进行尺寸计算, 或者对遏制盒的父元素进行适合内容尺寸计算。

  2. 对尺寸遏制盒及其内容进行布局,在概念上分为 两个阶段:

    按空内容进行 尺寸计算
    遏制盒的使用 width 和 height 按照对该盒执行正常布局的方式确定, 不同之处在于,它被视为没有任何内容——甚至不包括通过诸如 ::before、::after 或 ::marker 这样的伪元素产生的内容。

    替换元素必须被视为具有 0 的自然宽度和高度, 并且没有自然宽高比。

    注: 尺寸遏制仅抑制自然宽高比, 因此像 aspect-ratio 这样直接影响该首选宽高比的属性 仍会生效。

    尺寸遏制盒的所有 CSS 属性都会像 正常执行布局时一样被考虑。 其他规范可能会规定特定的例外情况。

    注: 即使元素的尺寸属性指定了固有尺寸, 这也不一定会使元素的尺寸变为零: 元素自身设置的属性 仍会被考虑, 这可能会使其变得更大。

    原位 布局
    然后必须将遏制盒的内容 (包括任何伪元素) 正常布局到此时尺寸已固定的遏制盒中。

    注: 尺寸遏制不会抑制基线对齐。 有关这一点,请参见布局 遏制。

  3. 尺寸 遏制盒是不可分割的(参见 CSS 分片 3 § 4.1 可能的分断点)。

给定以下标记和样式,图像会被调整为100px x 100px,因为长宽比属性生效。
img {
  width: 100px;
  aspect-ratio: 1/1;
  contain: size;
}
<img src="https://www.example.com/300x100.jpg">

如果未声明长宽比属性,图像将为100px x 0px,因为其自然长宽比被抑制,其自然高度被视为0。

然而,当满足以下任意条件时,为一个元素赋予尺寸容器将无效:

注意:内部表格框,不包括表格标题栏,被排除在外,因为表格布局算法不允许框比其流入内容更小。将表格单元格按空布局并在内部布局其内容而不改变尺寸,实际上是未定义的操作。手动将宽度或高度属性设置为0不能使其比内容更小。这一问题不适用于表格标题栏,它们完全可以具有独立于其内容的固定大小。

3.1.1. 可能的尺寸容器优化

本节为非规范性内容。

单独来看,尺寸 遏制并没有提供太多优化机会。 它自身的主要好处是,那些希望根据遏制盒的尺寸 来布局遏制盒内容的工具 (例如实现“容器查询”概念的 JS 库) 可以这样做而不必担心出现“无限循环”, 即让子元素的尺寸响应遏制 盒的尺寸会导致遏制盒的尺寸也发生变化, 从而可能触发子元素调整自身尺寸方式的进一步变化, 并因此可能导致遏制盒的尺寸发生更多变化, 如此无限循环。

不过,当与布局 遏制配合使用时, 可以启用的优化包括(但不限于):

  1. 当遏制盒的后代的样式或内容发生更改时, 在计算 DOM 树的哪些部分被“标记为脏”并可能需要重新布局时, 可以在遏制盒处停止。

  2. 在布局页面时, 如果遏制盒位于屏幕之外或被遮挡, 则其内容的布局(即“原位布局”)可以延迟进行或以较低 优先级进行。

3.2. 布局容器

为一个元素赋予布局容器会使其主框成为一个布局容器框,并具有以下效果:

  1. 布局遏制盒建立一个独立的格式化 上下文。

  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。

  3. 如果 overflow 属性的计算值 是 visible 或 clip,或者二者的组合, 则任何溢出都必须被视为墨水 溢出。

  4. 布局遏制盒建立一个绝对定位包含块和 一个固定定位包含块。

  5. 布局遏制盒创建一个层叠上下文。

  6. 强制分断允许出现在布局遏制盒内部, 但不会像CSS 分片 3 § 3.1 盒之间的分断:break-before 和 break-after 属性中所述的其他情况那样传播到父级。

    注: 这引入了此前不存在的一种可能性, 即强制分断可能发生在盒与其容器之间(参见CSS 分片 3 § 4.1 可能的分断点)。

  7. 对于 vertical-align 属性, 或任何其他其效果需要将布局遏制盒的基线位置 与其后代以外的某个对象相关联的属性而言, 遏制盒被视为没有 基线。

然而,当满足以下任意条件时,为一个元素赋予布局容器将无效:

3.2.1. 可能的布局容器优化

本节为非规范性内容。

布局容器可能启用的优化包括(但不限于):

  1. 在布局页面时,单独的容器框的内容可以并行布局,因为它们保证不会相互影响。

  2. 在布局页面时,如果容器框不在屏幕上或被遮挡,并且屏幕上可见部分的布局不依赖于容器框的大小(例如,如果容器框接近块级容器的末尾,而你正在查看块级容器的开头),则容器框内容的布局可以延迟或以较低优先级完成。

    (当与尺寸容器配合使用时,此优化可以更广泛地应用。)

3.3. 样式容器

为一个元素赋予样式容器会产生以下效果:

  1. counter-increment和counter-set属性必须限定在元素的子树内,并创建一个新的计数器。

  2. content属性的open-quote、close-quote、no-open-quote和no-close-quote的效果必须限定在元素的子树内。

    注意: 这意味着子树中的引用嵌套深度保持不变,并从其上下文通常暗示的值开始,但这些值在子树内对引用嵌套深度的更改不会影响子树外的引用嵌套深度。

注意: [CSS-REGIONS-1]对样式容器如何影响区域有规范性要求。

限定属性的效果被限定在特定元素或子树内。

由于counter-increment被限定在元素的子树内,因此子树内的第一次使用表现得好像在限定元素处将命名计数器设置为0,无论该计数器是否在限定元素外使用过。子树内的任何增量对限定元素外的同名计数器没有影响。但是,counter()和counters()的content属性值本身并未限定,可以引用在子树外建立的计数器。因此,以下代码将显示为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. 可能的样式容器优化

本节为非规范性内容。

样式容器可能启用的优化包括(但不限于):

  1. 当一个具有样式容器的元素的后代元素上的属性发生变化时,计算DOM树的哪些部分被“弄脏”并可能需要重新计算样式,可以在具有样式容器的元素处停止。

3.4. 绘制容器

为一个元素赋予绘制容器会使其主框成为一个绘制容器框,并具有以下效果:

  1. 元素的内容(包括任何墨水溢出或可滚动溢出)必须剪裁到溢出剪裁边缘的绘制容器框内,考虑[[css-backgrounds-3#corner clipping|角剪裁]]。这不包括创建任何机制来访问或指示被剪裁内容的存在;也不妨碍通过其他属性创建任何此类机制,例如溢出、调整大小或文本溢出。

    注意: 此剪裁形状尊重overflow-clip-margin,允许具有绘制容器的元素仍然稍微超出其正常边界。

    注意: 本段描述的行为相当于在使用值时将overflow-x: visible更改为overflow-x: clip,并将overflow-y: visible更改为overflow-y: clip,而其他overflow-x和overflow-y的值保持不变。

  2. 绘制容器框建立一个绝对定位包含块和固定定位包含块。

  3. 绘制容器框创建一个堆叠上下文。

  4. 绘制容器框 建立一个独立的格式化上下文。

然而,当满足以下任意条件时,为一个元素赋予绘制容器将无效:

3.4.1. 可能的绘制容器优化

本节为非规范性内容。

绘制容器可能启用的优化包括(但不限于):

  1. 如果容器框不在屏幕上或被遮挡,UA通常可以跳过尝试绘制其内容,因为它们也保证处于屏幕外/被遮挡状态。

    注意: 某 些绘制效果(如blur()滤镜)具有非局部效果。用户代理需要跟踪这些效果,因为当其后代发生变化时,即使它们具有绘制容器且本可以跳过,也可能需要重新绘制带有此类滤镜的元素的部分内容。

  2. 除非通过其他机制(如溢出、调整大小或文本溢出属性)使剪裁内容可访问,UA可以为该框保留与框大小完全一致的“画布”空间。(在类似的可滚动情况下,如overflow: hidden,可以滚动到当前被剪裁的内容,所以UA通常会预见性地多绘制一些,以便在滚动发生时立即显示内容,而不是在稍后的一帧中显示。)

  3. 因为它们保证是堆叠上下文,滚动元素可以绘制到单个GPU图层中。

4. 完全抑制元素的内容:content-visibility属性

名称: content-visibility
值: visible | auto | hidden
初始值: visible
适用于: 可以应用布局容器的元素
继承: 否
百分比: 不适用
计算值: 按指定值
规范顺序: 按语法
动画类型: 不可动画

content-visibility属性控制元素是否完全渲染其内容,同时强制实施一系列容器,允许用户代理在需要之前省略大量布局和渲染工作。该属性具有以下值:

visible

无效。元素的内容按常规布局和渲染。

hidden

元素跳过其内容。

跳过的内容必须对用户代理功能(例如页面查找、Tab顺序导航等)不可访问,也不可选中或聚焦。

注意: 这类似于将内容设置为display: none。

auto

为元素开启布局容器、样式容器和绘制容器。

如果该元素对用户不相关,它也会跳过其内容。

与hidden不同,跳过的内容必须仍然可以被用户代理功能正常访问,例如页面查找、Tab顺序导航等,并且必须能够正常聚焦和选择。

当一个元素跳过其内容时,用户代理必须更改使用值的contain属性,以便为布局容器、样式容器、绘制容器和尺寸容器启用。进一步的,其内容(该元素的扁平树后代,包括文本和元素,或替换元素的替换内容)不会被绘制(就像它们具有visibility: hidden)并且不会响应点击测试(就像它们具有pointer-events: none),并且在很大程度上不会更新其样式,除非通过脚本明确请求(有关详细信息,请参见§ 4.4 限制和说明)。

用户代理应尽可能避免对跳过的内容进行布局/渲染工作;重度容器和使内容不可见且不可触摸的组合允许进行重度优化。如果某个时刻进行了渲染工作,用户代理应保留先前计算的布局状态,以便稍后可以快速显示跳过的内容。

如果一个元素的值不是content-visibility: visible,则以下属性成立:
  • 布局容器确保用户代理能够在跳过的子树中省略布局工作,因为这种布局的结果不会影响容器元素外的元素。

  • 样式容器确保在跳过的子树中不需要处理计数器,因为它们不会影响容器元素外的计数器。

  • 绘制容器确保绘制内容的墨水溢出被剪裁;这反过来意味着用户代理可以可靠地确定元素的可见部分何时接近视口(并且,对于content-visibility: auto,开始绘制它)。

  • 尺寸容器确保用户代理能够在跳过的子树中省略布局,因为这种布局的结果不会影响容器元素的大小。

请注意,在content-visibility: auto的情况下,即使元素未被跳过,布局容器、样式容器和绘制容器仍然存在。这是为了防止由于元素进入和退出跳过状态而导致的容器更改所引起的布局变化。

如果以下任一条件为真,则元素与 用户相关:

4.1. 使用content-visibility: hidden

本节为非规范性内容。

content-visibility: hidden对元素施加了强大的限制,因此应谨慎使用。它还启用了一些非常有用的场景,通常改进了现有技术,以下是其中一些。

  1. 如果页面需要对不会被渲染的元素或文本进行一些测量,通常会将要测量的内容定位到屏幕外,使用类似于position: absolute; left: -100000px;,然后调用类似getBoundingClientRect()的API。

    不幸的是,即使页面从未打算显示这些内容,用户代理仍然必须为这些内容执行完整的样式、布局和渲染工作,以防它影响屏幕上的显示。作者也不能保证内容不会意外出现在屏幕上;即使是非常负的left值(如上所述)可能也不足以确保这一点,具体取决于内容。

    将这些内容包装在一个content-visibility: hidden容器中解决了所有这些问题。如果包装器没有边框、背景等,那么它和它的跳过的内容保证永远不会渲染到屏幕上,无论它们有多大。因为内容被跳过,用户代理也可以避免对其进行样式处理或布局,直到脚本最终需要时。

  2. 一个“单页应用程序”通常由几个独立的窗格或“视图”组成,其中只有一个同时显示。

    如果作者想要避免为非活动视图支付样式/布局/渲染等成本,他们可以将其完全从文档中移除,或者至少对其应用display:none。不幸的是,这意味着当视图确实需要显示时,所有样式/布局/渲染等工作都需要一次性完成,可能会导致视图实际显示之前的明显延迟。

    或者,可以将视图定位到屏幕外。这意味着当需要使用时,它将立即准备好,但它会一直消耗样式/布局/渲染的成本,这可能是显著的,特别是如果有许多非活动视图。非活动视图也可能仍然会出现在辅助工具中,混淆使用屏幕阅读器的用户、使用Ctrl-F进行页面查找的人等。

    content-visibility: hidden改进了这两种选项。因为内容被跳过,当它们不活动时,用户代理不会花费时间在它们上。它们也不会对屏幕阅读器、页面查找和其他工具可见。并且因为用户代理应尽可能保留以前的样式/布局工作,如果视图以前已经显示过,重新渲染它可能会非常快。

  3. 如果作者想让一个元素“不可见”,但仍然在页面中显示以用于布局目的,一个选项是visibility: hidden。然而,visibility: hidden元素的后代可以设置visibility: visible并重新显示,这并不总是直观或预期的。

    content-visibility: hidden执行非常类似的功能,但后代无法“关闭”它并开始显示;它们保持“隐藏”,直到祖先关闭它。

    因为content-visibility: hidden还将许多容器值应用于容器,它并不总是像visibility: hidden那样可用,但当其限制可以接受时,它可以是一种更可靠、更一致的方式来隐藏元素的内容。

4.2. 使用content-visibility: auto

本节为非规范性内容。

content-visibility: auto比hidden更复杂;它不是类似于display: none,而是随着元素的内容变得与用户相关时,自适应地隐藏/显示元素的内容。它也不会将其跳过的内容从用户代理中隐藏,因此屏幕阅读器、页面查找和其他工具仍然可以与其交互。

最好将其视为对容器的升级:如果作者有大量内容需要显示,并且这些内容通常会在屏幕外(例如一个可滚动的长列表),并且该内容可以接受重度容器,他们应该考虑使用content-visibility: auto一次性应用所有的容器。这也强烈暗示用户代理可以跳过内容的工作(可能会导致内容进入屏幕时出现小延迟),因为文档中有大量内容,其中大部分内容无论如何都不会被看到。

注意:因此,content-visibility: auto可以替代复杂的“虚拟列表”技术,至少在许多情况下可以如此。

由于content-visibility: auto只有在元素的内容对用户不相关时才会导致元素跳过其内容,因此最好在合理细粒度下使用。

例如,在Twitter上,将content-visibility: auto应用于整个时间线并不会产生多大效果——它总是在屏幕上,因此它永远不会跳过其内容。

相反,content-visibility应该应用于单个推文,允许它们在离开屏幕时被跳过。

由于content-visibility: 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属性描述:

skipped, 类型为boolean,只读

如果目标状态更改为跳过其内容,则设置为true,否则为false。

ContentVisibilityAutoStateChangedEventInit成员描述:

skipped, 类型为boolean,默认值为false

请参阅skipped属性的描述。

请注意,即使在content-visibility: auto子树中的元素跳过其内容,它们仍然在语义上与元素相关。这意味着使用此信号无限期地跳过被跳过子树中的DOM更新是不合适的。相反,它应该用于降低更新的优先级,但确保内容在语义上保持相关并且合理地保持最新。这对于即使在祖先设置为跳过其内容时仍然使用这些内容的辅助技术尤为重要。

4.4. 限制和澄清

  1. 从 IntersectionObserver 的角度来看, 元素的被跳过的 内容 永远不会与交叉根相交。 即使根元素和目标元素 都位于被跳过的内容中,也是如此。

  2. 从 ResizeObserver 的角度来看, 元素的被跳过的 内容 永远不会改变其大小。 如果这些元素随后变为不再被跳过, 并且新大小与上次用于通知调整大小观察器的大小不同, 则会传递调整大小观察结果。

  3. 如果元素开始或停止跳过其内容, 此更改会在 渲染该更改效果的帧的 requestAnimationFrame 回调 运行之后发生。 具体来说,此类更改将在处理模型的更新渲染步骤的第 13 步和第 14 步之间生效 (即“运行动画帧回调” 和“运行更新交叉观察步骤”之间)。

    确定元素与视口的交叉情况 可以使用 IntersectionObserver 的内部版本来完成。 但是,由于由此产生的观察结果会在 更新渲染的第 14 步分派, 因此对跳过(进而是绘制)状态的任何更改 直到下一帧处理时才会对用户可见。 因此,更新跳过状态, 包括遏制调整, 也会推迟到该帧进行。 这可确保脚本在这两个事件之间访问, 例如, 元素的遏制值 (内部交叉观察和跳过状态 更新) 时,将获取与当前绘制状态一致的值, 并且不会导致任何强制布局。
  4. 对于 content-visibility: auto,初始可见性判定必须 与判定存在新的 content-visibility: auto 元素在同一帧中 发生。

    当元素首次获得 content-visibility: auto 时,它可能位于屏幕上,也可能不在 屏幕上。对此状态的判定,进而 对该元素是否被跳过的判定,必须在 同一帧中发生。否则,就有可能在元素所在位置产生空白 内容,因为可见性检查和跳过状态 更新将被推迟到下一帧。
  5. 对于滚动操作, 例如 scrollIntoView(), 具有 content-visibility: auto 且正在跳过其 内容的元素,其大小和位置是在尺寸遏制仍然有效的情况下确定的。

    注: 一旦滚动到视图中, 元素将不再跳过其内容, 因此可能不再具有尺寸遏制; 如果这改变了元素的大小, 它在视口中的对齐可能不会完全符合请求。

    如果某个元素对用户代理特性不可用 (例如,如果它由于具有 content-visibility: hidden 的祖先而被跳过), 那么滚动操作 完全不得滚动到该元素, 就像它没有布局盒一样。

  6. 如果具有 content-visibility: auto 且正在跳过其 内容的元素获得焦点 (或其内容获得焦点), 则它会在因获得焦点而滚动到视图中之前变得与用户相关(因而停止跳过其内容)。

    注: 因此,与上一点不同, 元素的大小和在视口中的对齐将是正确的。 这与 focus() 方法的步骤顺序一致。

  7. 如果 iframe 跳过其 内容,或者属于某个元素的被跳过的 内容的一部分, 如果可能,用户代理应完全跳过 iframe 事件循环中的更新渲染步骤。

    注: 在 iframe 开始被跳过时, 它至少需要运行一次该步骤 以移除已绘制的输出。

  8. 被跳过的 内容不会计入 innerText 的结果。

  9. 当元素被跳过时, 元素上的 CSS 过渡和动画不会更新:

    • 即使新应用的样式会启动动画,也不会创建新的动画。

    • 现有动画不会沿其时间线推进。

    • 元素上正在运行的动画不会结束。

    如果脚本查询一个被跳过元素的样式 (从而导致样式更改事件), 并且为了返回正确信息而需要知道动画或过渡的状态, 则会根据该样式更改 事件发生时的样式 对动画和过渡进行采样:

    CSS 动画 2 § 4 动画事件和CSS 过渡 2 § 5 过渡事件定义了动画或过渡更新时 会创建哪些对象、 会触发哪些事件, 以及这些事件携带哪些数据。

    当元素停止被跳过时, 会对动画和过渡进行采样, 随后它们会从该点开始照常沿各自的时间线继续推进。

    注: 总体而言,这类似于 后台标签页重新回到前台时 过渡/动画的行为, 允许用户代理尽可能跳过不必要的动画工作, 同时又不会在动画重新变得相关时对其造成过多干扰。

  10. 当元素被跳过时, 它不得启动任何过渡, 即使样式更改事件影响了其计算样式。

    当元素停止被跳过时, 它不得因与其不再被跳过相关联的样式更改事件 而启动任何过渡。

    注: 这类似于元素从 display:none 切换为非 none 值——即使在这种情况下样式 从技术上讲确实发生了变化 (从它们的初始值 变为层叠产生的“正确”值), 也不会启动任何过渡。

  11. 如果元素有一个具有 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: 50px;
}
</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: 10px;
  top: 20px;
}
#child {
  position: relative;
  left: 1px;
  top: 2px;
  width: 100px;
  height: 200px;
}
</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 工作草案以来的变更

自2020-06-03 工作草案以来的变更

自2019-11-11 工作草案以来的变更

自CSS 包含级别 1以来的变更

一致性

文档约定

一致性要求通过描述性断言和 RFC 2119 术语的组合表达。本规范中的“必须(MUST)”、“不得(MUST NOT)”、“需要(REQUIRED)”、“应(SHALL)”、“不应(SHALL NOT)”、“应该(SHOULD)”、“不应该(SHOULD NOT)”、“建议(RECOMMENDED)”、“可以(MAY)”和“可选(OPTIONAL)”等关键词应按照 RFC 2119 的描述进行解释。然而,为了可读性,本规范中的这些词语并未全部使用大写字母。

除明确标记为非规范性部分的章节、示例和注释外,本规范的所有文本均为规范性内容。[RFC2119]

本规范中的示例以“例如”一词开头,或与规范性文本分开设置,并带有 class="example",如下所示:

这是一个信息性示例。

信息性注释以“注”字开头,并带有 class="note" 与规范性文本分开设置,如下所示:

注意,这是一条信息性注释。

建议是引起特别注意的规范性部分,并带有 <strong class="advisement",如下所示:用户代理必须提供一个可访问的替代方案。

一致性类别

本规范的一致性定义为以下三个一致性类别:

样式表
CSS 样式表。
渲染器
用户代理(UA),用于解释样式表的语义并渲染使用它们的文档。
创作工具
用户代理(UA),用于编写样式表。

如果样式表中使用了本模块定义的语法的所有声明均符合通用 CSS 语法及本模块中定义的各个特性语法,则该样式表符合本规范。

如果渲染器不仅能够按照适当的规范解释样式表,还能够通过正确解析本规范定义的所有特性并相应地渲染文档,则该渲染器符合本规范。然而,如果用户代理由于设备限制无法正确渲染文档,并不意味着该用户代理不符合规范。(例如,用户代理不要求在单色显示器上渲染颜色。)

如果创作工具编写的样式表在语法上符合通用 CSS 语法和本模块中每个特性的语法,并满足本模块中描述的样式表的所有其他一致性要求,则该创作工具符合本规范。

部分实现

为了使作者能够利用向前兼容的解析规则分配回退值,CSS 渲染器必须将其无法使用的所有 at-rules、属性、属性值、关键词和其他语法结构视为无效(并适当地忽略)。特别是,用户代理不得在单个多值属性声明中有选择性地忽略不受支持的组件值并使用受支持的值:如果任何值被认为无效(因为不受支持的值必须是无效的),CSS 要求忽略整个声明。

不稳定和专有功能的实现

为了避免与未来稳定的 CSS 功能发生冲突,CSSWG 建议遵循最佳实践,以实现不稳定的功能和 CSS 的专有扩展。

非实验性实现

一旦规范达到候选推荐阶段,便可以进行非实验性实现,且实现者应发布根据规范证明正确实现的任何 CR 级功能的无前缀实现。

为了建立和维护 CSS 在不同实现之间的互操作性,CSS 工作组要求非实验性 CSS 渲染器在发布任何 CSS 功能的无前缀实现之前,向 W3C 提交实现报告(如果需要,还要提交用于该实现报告的测试用例)。提交给 W3C 的测试用例需经 CSS 工作组审核和修正。

有关提交测试用例和实现报告的详细信息,请访问 CSS 工作组的网站:https://www.w3.org/Style/CSS/Test/。如有疑问,请发送邮件至 public-css-testsuite@w3.org 邮件列表。

索引

本规范定义的术语

引用定义的术语

参考文献

规范性引用

[CSS-BACKGROUNDS-3]
Bert Bos; Elika Etemad; Brad Kemper. CSS Backgrounds and Borders Module Level 3. 2021年7月26日. CR. URL: https://www.w3.org/TR/css-backgrounds-3/
[CSS-BOX-4]
Elika Etemad. CSS Box Model Module Level 4. 2020年4月21日. WD. URL: https://www.w3.org/TR/css-box-4/
[CSS-BREAK-3]
Rossen Atanassov; Elika Etemad. CSS Fragmentation Module Level 3. 2018年12月4日. CR. URL: https://www.w3.org/TR/css-break-3/
[CSS-CASCADE-5]
Elika Etemad; Miriam Suzanne; Tab Atkins Jr.. CSS Cascading and Inheritance Level 5. 2022年1月13日. CR. URL: https://www.w3.org/TR/css-cascade-5/
[CSS-CONTAIN-1]
Tab Atkins Jr.; Florian Rivoal. CSS Containment Module Level 1. 2020年12月22日. REC. URL: https://www.w3.org/TR/css-contain-1/
[CSS-CONTENT-3]
Elika Etemad; Dave Cramer. CSS Generated Content Module Level 3. 2019年8月2日. WD. URL: https://www.w3.org/TR/css-content-3/
[CSS-DISPLAY-3]
Tab Atkins Jr.; Elika Etemad. CSS Display Module Level 3. 2021年9月3日. CR. URL: https://www.w3.org/TR/css-display-3/
[CSS-IMAGES-3]
Tab Atkins Jr.; Elika Etemad; Lea Verou. CSS Images Module Level 3. 2020年12月17日. CR. URL: https://www.w3.org/TR/css-images-3/
[CSS-INLINE-3]
Dave Cramer; Elika Etemad; Steve Zilles. CSS Inline Layout Module Level 3. 2020年8月27日. WD. URL: https://www.w3.org/TR/css-inline-3/
[CSS-LISTS-3]
Elika Etemad; Tab Atkins Jr.. CSS Lists and Counters Module Level 3. 2020年11月17日. WD. URL: https://www.w3.org/TR/css-lists-3/
[CSS-OVERFLOW-3]
David Baron; Elika Etemad; Florian Rivoal. CSS Overflow Module Level 3. 2021年12月23日. WD. URL: https://www.w3.org/TR/css-overflow-3/
[CSS-POSITION-3]
Elika Etemad; Tab Atkins Jr.. CSS Positioned Layout Module Level 3. 2022年9月1日. WD. URL: https://www.w3.org/TR/css-position-3/
[CSS-PSEUDO-4]
Daniel Glazman; Elika Etemad; Alan Stearns. CSS Pseudo-Elements Module Level 4. 2020年12月31日. WD. URL: https://www.w3.org/TR/css-pseudo-4/
[CSS-SCOPING-1]
Tab Atkins Jr.; Elika Etemad. CSS Scoping Module Level 1. 2014年4月3日. WD. URL: https://www.w3.org/TR/css-scoping-1/
[CSS-SIZING-3]
Tab Atkins Jr.; Elika Etemad. CSS Box Sizing Module Level 3. 2021年12月17日. WD. URL: https://www.w3.org/TR/css-sizing-3/
[CSS-TRANSITIONS-1]
David Baron; et al. CSS Transitions. 2018年10月11日. WD. URL: https://www.w3.org/TR/css-transitions-1/
[CSS-UI-3]
Tantek Çelik; Florian Rivoal. CSS Basic User Interface Module Level 3 (CSS3 UI). 2018年6月21日. REC. URL: https://www.w3.org/TR/css-ui-3/
[CSS-UI-4]
Florian Rivoal. CSS Basic User Interface Module Level 4. 2021年3月16日. WD. URL: https://www.w3.org/TR/css-ui-4/
[CSS-VALUES-3]
Tab Atkins Jr.; Elika Etemad. CSS Values and Units Module Level 3. 2019年6月6日. CR. URL: https://www.w3.org/TR/css-values-3/
[CSS-VALUES-4]
Tab Atkins Jr.; Elika Etemad. CSS Values and Units Module Level 4. 2021年12月16日. WD. URL: https://www.w3.org/TR/css-values-4/
[CSS-WRITING-MODES-3]
Elika Etemad; Koji Ishii. CSS Writing Modes Level 3. 2019年12月10日. REC. URL: https://www.w3.org/TR/css-writing-modes-3/
[CSS-WRITING-MODES-4]
Elika Etemad; Koji Ishii. CSS Writing Modes Level 4. 2019年7月30日. CR. URL: https://www.w3.org/TR/css-writing-modes-4/
[CSS2]
Bert Bos; et al. Cascading Style Sheets Level 2 Revision 1 (CSS 2.1) Specification. 2011年6月7日. REC. URL: https://www.w3.org/TR/CSS21/
[CSSOM-VIEW-1]
Simon Pieters. CSSOM View Module. 2016年3月17日. WD. URL: https://www.w3.org/TR/cssom-view-1/
[DOM]
Anne van Kesteren. DOM Standard. 现行标准. URL: https://dom.spec.whatwg.org/
[FULLSCREEN]
Philip Jägenstedt. Fullscreen API Standard. 现行标准. URL: https://fullscreen.spec.whatwg.org/
[HTML]
Anne van Kesteren; et al. HTML Standard. 现行标准. URL: https://html.spec.whatwg.org/multipage/
[INTERSECTION-OBSERVER]
Stefan Zager; Emilio Cobos Álvarez. Intersection Observer. 2022年7月6日. WD. URL: https://www.w3.org/TR/intersection-observer/
[RESIZE-OBSERVER-1]
Aleks Totic; Greg Whitworth. Resize Observer. 2020年2月11日. WD. URL: https://www.w3.org/TR/resize-observer-1/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. 1997年3月. 最佳现行规范. URL: https://datatracker.ietf.org/doc/html/rfc2119
[SVG2]
Amelia Bellamy-Royds; et al. Scalable Vector Graphics (SVG) 2. 2018年10月4日. CR. URL: https://www.w3.org/TR/SVG2/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL Standard. 现行标准. URL: https://webidl.spec.whatwg.org/

参考性引用

[CSS-GRID-2]
Tab Atkins Jr.; Elika Etemad; Rossen Atanassov. CSS Grid Layout Module Level 2. 2020年12月18日. CR. URL: https://www.w3.org/TR/css-grid-2/
[CSS-MULTICOL-1]
Florian Rivoal; Rachel Andrew. CSS Multi-column Layout Module Level 1. 2021年10月12日. CR. URL: https://www.w3.org/TR/css-multicol-1/
[CSS-OVERFLOW-4]
David Baron; Florian Rivoal. CSS Overflow Module Level 4. 2017年6月13日. WD. URL: https://www.w3.org/TR/css-overflow-4/
[CSS-PAGE-3]
Elika Etemad; Simon Sapin. CSS Paged Media Module Level 3. 2018年10月18日. WD. URL: https://www.w3.org/TR/css-page-3/
[CSS-REGIONS-1]
Rossen Atanassov; Alan Stearns. CSS Regions Module Level 1. 2014年10月9日. WD. URL: https://www.w3.org/TR/css-regions-1/
[CSS-SIZING-4]
Tab Atkins Jr.; Elika Etemad; Jen Simmons. CSS Box Sizing Module Level 4. 2021年5月20日. WD. URL: https://www.w3.org/TR/css-sizing-4/
[FILTER-EFFECTS-1]
Dirk Schulze; Dean Jackson. Filter Effects Module Level 1. 2018年12月18日. WD. URL: https://www.w3.org/TR/filter-effects-1/

属性索引

名称 值 初始值 应用于 继承 百分比 动画类型 标准顺序 计算值
contain none | strict | content | [ size || layout || style || paint ] none 见下文 否 不适用 不可动画 按照语法 关键字 none 或 size、layout、paint 中的一个或多个
content-visibility visible | auto | hidden visible 适用于可以应用布局封闭的元素 否 不适用 不可动画 按照语法 按指定值

IDL 索引

[Exposed=Window]
interface ContentVisibilityAutoStateChangedEvent : Event {
  constructor(DOMString type, optional ContentVisibilityAutoStateChangedEventInit eventInitDict = {});
  readonly attribute boolean skipped;
};
dictionary ContentVisibilityAutoStateChangedEventInit : EventInit {
  boolean skipped = false;
};