使用 CSS 局限
CSS 局限(CSS containment)通过允许浏览器将页面的一个子树与页面的其余部分隔离,以提高网页的性能。如果浏览器知道页面的某个部分与其余内容是独立的,就可以优化渲染并提升性能。
contain
和 content-visibility
属性使开发者能够告知用户代理是否应该渲染元素的内容,以及在元素不在屏幕上时是否应渲染其内容。然后,用户代理在适当的时候对元素应用局限,可能会推迟布局和渲染,直到需要时再进行。
本指南描述了 CSS 局限的基本目标以及如何利用 contain
和 content-visibility
来提升用户体验。
基本示例
网页通常包含多个逻辑上相互独立的部分。CSS 局限使它们在渲染时真正独立处理。
例如,博客通常包含几篇文章,每篇文章包含一个标题和内容,如以下标记所示。
<h1>我的博客</h1>
<article>
<h2>一篇美文的标题</h2>
<p>一些内容。</p>
</article>
<article>
<h2>另一篇美文的标题</h2>
<p>更多内容。</p>
</article>
使用 CSS,我们对每个文章应用 contain
属性,并赋值为 content
。content
值是 contain: layout paint style
的简写:
article {
contain: content;
}
从逻辑上讲,每篇文章都是独立于页面上其他文章的。这些信息通常是已知的,并且对于创建页面的网页开发者来说可能相当明显。然而,浏览器不了解内容的意图,无法假设文章或其他内容部分将完全自包含。
这个属性提供了一种向浏览器解释这一点并明确授权其进行性能优化的方法。它告诉浏览器元素的内部布局与页面的其余部分完全独立,元素的所有内容都在其边界内绘制。没有任何内容可以可见地溢出。
通过在每个 <article>
上设置 contain: content
,我们已经表明了这一点;我们告诉浏览器每篇文章都是独立的。然后,浏览器可以利用这些信息来决定如何渲染每个 <article>
内容。例如,它可能不会渲染不在可视区域内的文章。
当在页面末尾追加更多文章时,浏览器无需重新计算布局或重绘前面的内容;它也不需要触及包含元素子树之外的任何区域。然而,如果盒模型属性是相互依赖的,浏览器将需要重新计算布局和重绘。例如,如果 <article>
的样式使其尺寸取决于其内容(例如使用 height: auto
),则浏览器需要考虑其尺寸的变化。
关键概念和术语
contain
值
局限有四种类型:布局(layout)、绘制(paint)、尺寸(size)和样式(style)。使用 contain
属性通过包含这些类型的任何组合来指定要应用于元素的类型或类型。
布局局限
article {
contain: layout;
}
布局通常限定在整个文档范围,这意味着如果移动一个元素,整个文档需要被视为可能有任何元素移动。通过使用 contain: layout
,你可以告诉浏览器它只需要检查这个元素——元素内部的所有内容都限定在该元素内,并且不影响页面的其余部分,包含盒子建立了一个独立的格式化上下文。
此外:
float
布局将在指定元素内独立执行。- 外边距不会跨越布局局限边界折叠。
- 布局容器是
absolute
和fixed
定位子元素的包含块。 - 包含盒子创建了一个层叠上下文,因此可以使用
z-index
。
备注:
当使用 container-type
和 container-name
属性时,contain
的 style
和 layout
值会自动应用。
绘制局限
article {
contain: paint;
}
绘制局限本质上将盒子裁剪到主盒子的内边距边缘。不能有可见的溢出。paint
局限的其他附加说明与 layout
局限相同(见上文)。
另一个优点是,如果应用了局限的元素不在屏幕上,浏览器不需要绘制其子元素——因为它们完全被该盒子包含,也不在屏幕上。
尺寸局限
article {
contain: size;
}
单独使用尺寸局限时,性能优化并不显著。然而,尺寸局限意味着被尺寸局限限制的元素的子元素的尺寸不能影响元素本身的尺寸——其尺寸的计算方式就好像它没有子节点一样。
如果在元素上设置 contain: size
,需要使用 contain-intrinsic-size
或顺序为 contain-intrinsic-width
和 contain-intrinsic-height
的全称属性来指定元素的尺寸。如果没有设置尺寸,元素在大多数情况下可能会变为零尺寸。
article {
contain: size;
contain-intrinsic-size: 100vw auto;
}
样式局限
article {
contain: style;
}
尽管名称如此,样式局限并不提供像影子 DOM 或 @scope
那样的域限(scoped)样式。style
值的主要用途为防止 CSS 计数器可在元素中被更改的情形出现,此情形可影响树的其余部分。
使用 contain: style
将确保由 counter-increment
和 counter-set
属性所创建的新计数器的作用域被限制为此子树。
你可以通过包含多个以空格分隔的值(如 contain: layout paint
)或使用两个特殊值之一来包含多个局限类型。
特殊值
contain
有两个特殊值,它们是前三种或所有四种局限类型的简写:
content
strict
我们在上面的示例中遇到了第一个。使用 contain: content
启用 layout
、paint
和 style
局限。由于它省略了 size
,因此是可以广泛应用的安全值。
contain: strict
声明的行为与声明 contain: size layout paint style
(包括四个以空格分隔的值)相同,提供了最大的局限。由于它应用了 size
局限,因此使用起来更具风险;存在由于依赖子元素的尺寸导致盒子最终变为零尺寸的风险。
为了消除这种风险,请在使用 strict
时始终设置尺寸:
article {
contain: strict;
contain-intrinsic-size: 80vw auto;
}
上述内容等同于:
article {
contain: size layout paint style;
contain-intrinsic-size: 80vw auto;
}
content-visibility
当你有大量内容且这些内容经常不在屏幕上时,你可以从重局限中受益——例如,如果所有博客文章都在博客首页上以无限滚动的方式可见——可以使用 content-visibility: auto
一次性应用所有局限。
content-visibility
属性控制元素是否渲染其内容,并强制应用一组强局限,允许用户代理有机会在不需要时省略大量布局和渲染工作。此属性使用户代理得以在不需要时跳过元素的渲染工作(包括布局和绘制)——由此使页面的初始加载明显变快。
其可能的值包括:
与用户相关
跳过其内容
当你在元素上设置 content-visibility: hidden
时,你告诉浏览器该元素与用户无关,因此其内容应被跳过并且不进行渲染。这有助于提升性能。
当在元素上设置 content-visibility: auto
并且浏览器确定其内容与用户无关时,浏览器也会跳过该元素的内容。
当元素跳过其内容时:
- 它启用了布局、样式、绘制和尺寸局限。
- 它的内容不会被绘制,就像设置了
visibility: hidden
一样。 - 它的内容不会接收指针事件,就像设置了
pointer-events: none
一样。
这两种情况下都会发生上述情况,但使用 content-visibility: auto
时,内容仍然可以被搜索、接收焦点,并且可以从不相关变为相关。而 content-visibility: hidden
则不具备这种情况。
备注:
要对从 content-visibility: hidden
到可见值的过渡进行动画处理,需要设置 transition-behavior: allow-discrete
和 @starting-style
样式。请参阅过渡 display
和 content-visibility
了解更多信息。
参见
- CSS 局限模块
- 学习:CSS 性能优化
- CSS 容器查询
- CSS 局限介绍,来自 Igalia.com(2019)
contentvisibilityautostatechange
事件