要点
借助新的 CSS Containment 属性,开发者可以限制浏览器样式、布局和绘制工作的范围。
它有几个值,其语法如下:
contain: none | strict | content | [ size || layout || style || paint ]
它已在 Chrome 52 及更高版本和 Opera 40 及更高版本中推出(并且获得了 Firefox 的公开支持),因此请试用一下,并告诉我们您的使用体验!
contain 属性
在制作 Web 应用甚至复杂的网站时,一个关键的性能挑战是限制样式、布局和绘制的影响。通常,对于计算工作,整个 DOM 都被视为“在范围内”,这可能意味着尝试在 Web 应用中实现自包含的“视图”可能会很棘手:DOM 的一部分发生变化可能会影响其他部分,并且无法告知浏览器哪些内容应在范围内或不在范围内。
例如,假设您的 DOM 的一部分如下所示:
<section class="view">
Home
</section>
<section class="view">
About
</section>
<section class="view">
Contact
</section>
您可以将新元素附加到一个 View,这将触发样式、布局和绘制:
<section class="view">
Home
</section>
<section class="view">
About
<div class="newly-added-element">Check me out!</div>
</section>
<section class="view">
Contact
</section>
不过,在这种情况下,整个 DOM 实际上都处于范围内,这意味着样式、布局和绘制计算必须考虑所有元素,无论这些元素是否发生了更改。DOM 越大,涉及的计算工作就越多,这意味着您的应用可能会对用户输入无响应。
好消息是,现代浏览器在自动限制样式、布局和绘制工作范围方面变得越来越智能,这意味着您无需执行任何操作,速度就会越来越快。
不过,更棒的是,有一个新的 CSS 属性可将范围控制权交给开发者:Containment。
CSS Containment 是一个新属性,其关键字为 contain,支持以下四个值:
layout
paint
size
style
通过这些值,您可以限制浏览器需要执行的渲染工作量。下面我们来详细了解一下每种值。
布局(包含:布局)
布局嵌套可能是封装的最大优势,与 contain: paint
并列。
布局通常是文档级范围的,因此会按 DOM 的大小成比例缩放,因此,如果您更改元素的 left
属性,则可能需要检查 DOM 中的每个元素。
在这里启用封装功能可能会将元素数量减少到只有一小部分(而不是整个文档),从而为浏览器节省大量不必要的工作并显著提升性能。
绘制(包含:绘制)
范围限定绘制是容器的另一个非常实用的优势。绘制容器本质上会剪裁相关元素,但它还有一些其他副作用:
- 它充当绝对定位元素和固定位置元素的容器块。这意味着,任何子元素的排列方式都基于具有
contain: paint
的元素,而不是任何其他父元素(例如文档)。 - 它会成为堆叠上下文。这意味着
z-index
等内容会对元素产生影响,并且子项将根据新上下文进行堆叠。 - 它会成为新的格式设置上下文。这意味着,例如,如果您有一个包含绘制容器的块级元素,系统会将其视为新的独立布局环境。这意味着,元素外部的布局通常不会影响包含元素的子元素。
尺寸(包含:尺寸)
contain: size
表示该元素的子元素不会影响父元素的尺寸,并且系统会使用其推断出的尺寸或声明的尺寸。因此,如果您设置了 contain: size
,但未为元素指定尺寸(直接或通过 flex 属性指定),则该元素将以 0px x 0px 的尺寸呈现!
尺寸控制实际上是一种双重保障措施,可确保您不依赖子元素来调整尺寸,但它本身不会带来太多性能优势。
样式(包含:style)
很难预测更改元素样式对 DOM 树的影响。例如,在 CSS 计数器中,更改子项中的计数器可能会影响文档中其他位置使用的同名计数器值。设置 contain: style
后,样式更改不会传播回包含元素。
需要明确指出的是,contain: style
不提供与 Shadow DOM 提供的范围限定样式相同的功能;这里的封装仅仅是指在样式发生变异时限制考虑范围内的树的部分,而不是在声明样式时。
严格限制和内容控制
您还可以组合关键字(例如 contain: layout paint
),这样系统只会将这些行为应用于元素。但 contain 还支持两个其他值:
contain: strict
的含义与contain: size layout paint
相同contain: content
的含义与contain: layout paint
相同
如果您事先知道元素的尺寸(或希望预留其尺寸),则使用严格的边界限制非常有用,但请注意,如果您不声明尺寸就声明了严格的边界限制,由于隐含的尺寸边界限制,元素可能会呈现为 0 像素 x 0 像素的框。
另一方面,内容容器可显著改善范围,但您无需提前了解或指定元素的尺寸。
在这两者中,contain: content
是您应默认使用的选项。如果 contain: content
不足以满足您的需求,您应将严格限制视为一种应急措施。
请告诉我们您的进展
利用封闭容器,您可以向浏览器指明您打算在网页中隔离哪些内容。欢迎在 Chrome 52 及更高版本中试用,并告诉我们您的使用体验!