使用 CSS 包含
CSS 包含通过允许浏览器将页面的子树与页面的其余部分隔离开来,从而提高网页的性能。如果浏览器知道页面的某个部分独立于其余内容,则可以优化渲染并提高性能。
contain
和 content-visibility
属性使开发人员能够告知用户代理是否应该完全渲染元素的内容,以及是否应该在元素处于屏幕外时渲染其内容。用户代理随后将在适当情况下将包含应用于元素,可能推迟布局和渲染,直到需要为止。
本指南描述了 CSS 包含的基本目标以及如何利用 contain
和 content-visibility
来获得更好的用户体验。
基本示例
网页通常包含多个部分,从逻辑上讲,这些部分彼此独立。CSS 包含使它们在渲染方面真正彼此独立。
例如,博客通常包含几篇文章,每篇文章都包含标题和内容,如下面的标记所示。
<h1>My blog</h1>
<article>
<h2>Heading of a nice article</h2>
<p>Content here.</p>
</article>
<article>
<h2>Another heading of another article</h2>
<p>More content here.</p>
</article>
使用 CSS,我们使用 contain
属性的值为 content
应用于每篇文章。content
值是 contain: layout paint style
的简写
article {
contain: content;
}
从逻辑上讲,每篇文章都独立于页面上的其他文章。此信息通常是创建页面的 Web 开发人员已知的,并且可能非常明显。但是,浏览器不知道您的内容的意图,不能假设文章或其他内容部分将完全独立。
此属性提供了一种向浏览器解释这一点并明确授权其进行性能优化的方式。它告诉浏览器元素的内部布局与页面的其余部分完全分开,并且元素的所有内容都在其边界内绘制。没有任何内容可以明显溢出。
通过在每个 <article>
上设置 contain: content
,我们已经指明了这一点;我们已经告诉浏览器每个文章都是独立的。然后,浏览器可以使用此信息来决定如何渲染每个 <article>
内容。例如,它可能不会渲染不在可视区域的文章。
当在页面末尾追加更多文章时,浏览器不需要重新计算布局或重新绘制前面的内容;它也不需要触碰包含元素子树之外的任何区域。但是,如果盒子模型属性依赖,则浏览器将需要重新计算布局和重新绘制。例如,如果 <article>
的样式设置使其大小取决于其内容(例如,使用 height: auto
),则浏览器将需要考虑其大小变化。
关键概念和术语
contain
值
有四种类型的包含:布局、绘制、大小和样式。使用 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;
}
尽管有这个名字,但样式包含并不提供像 Shadow DOM 或 `@scope` 那样作用于范围的样式。`style` 值的主要用例是防止 CSS 计数器 在元素中更改,然后可能影响树的其余部分的情况。
使用 `contain: style` 可确保 `counter-increment` 和 `counter-set` 属性创建仅作用于该子树的新计数器。
你可以通过包含多个用空格分隔的值来包含多个包含类型,例如 `contain: layout paint`,或者使用两种 特殊值 中的一种。
特殊值
`contain` 有两个特殊值,它们是前三个或所有四个包含类型的简写。
content
严格
我们在上面的示例中遇到了第一个。使用 `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` 事件