要点
新的 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 包含”是一种新属性,其关键字 include 支持以下四个值:
layout
paint
size
style
通过这些值,您可以限制浏览器需要执行的渲染工作量。下面我们来详细了解一下每种值。
布局(包含:布局)
布局嵌套可能是封装的最大优势,与 contain: paint
并列。
布局通常是文档级范围的,因此会按 DOM 的大小成比例缩放,因此,如果您更改元素的 left
属性,则可能需要检查 DOM 中的每个元素。
在这里启用封装功能可能会将元素数量减少到只有一小部分(而不是整个文档),从而为浏览器节省大量不必要的工作并显著提升性能。
绘制(包含:绘制)
作用域绘制是控制的另一个极为有用的好处。绘制容器本质上会剪裁相关元素,但它还有一些其他副作用:
- 它充当绝对定位元素和固定位置元素的容器块。这意味着,所有子元素的排列方式都基于具有
contain: paint
的元素,而不是任何其他父元素(例如文档)。 - 它会成为堆叠上下文。这意味着
z-index
等内容会对元素产生影响,并且子项将根据新上下文进行堆叠。 - 它会成为新的格式设置上下文。这意味着,例如,如果您有一个包含绘制容器的块级元素,系统会将其视为新的独立布局环境。这意味着,元素外部的布局通常不会影响包含元素的子元素。
尺寸(包含:尺寸)
contain: size
表示该元素的子元素不会影响父元素的尺寸,并且系统会使用其推断出的尺寸或声明的尺寸。因此,如果您设置 contain: size
,但未指定元素尺寸(直接或通过 Flex 属性指定),其渲染尺寸将为 0x0 像素!
尺寸限制实际上是一种双重保障措施,可确保您不依赖子元素来调整大小,但它本身不会带来太多性能优势。
样式(包含:style)
很难预测更改元素样式对 DOM 树的影响。例如 CSS 计数器,更改子级中的计数器可能会影响文档中其他位置使用的相同名称的计数器值。设置 contain: style
后,样式更改不会传播回包含元素。
特别要说明的是,contain: style
不提供的是从 Shadow DOM 获得的作用域样式设置;这里的包含纯粹是为了限制在更改样式时要考虑的树部分,而不是在声明样式时加以限制。
严格限制和内容控制
您还可以组合关键字(例如 contain: layout paint
),这样系统只会将这些行为应用于元素。但 contain 还支持两个其他值:
contain: strict
的含义与contain: size layout paint
相同contain: content
的含义与contain: layout paint
相同
如果您提前知道元素的尺寸(或希望保留其尺寸),那么使用严格包含是非常有用的,但请注意,如果您声明严格包含(不包含尺寸),由于暗含尺寸,该元素可能会呈现为 0x0 像素的方框。
另一方面,内容容器可显著改善范围,但您无需提前了解或指定元素的尺寸。
在这二者中,contain: content
是您应默认使用的一个。如果 contain: content
不足以满足您的需求,您应将严格限制视为一种应急措施。
请告诉我们您的进展
“包含”是一个不错的方法,可向浏览器指明您打算在网页中隔离什么。欢迎使用 Chrome 52 及以上版本来试用,并告诉我们您取得的成效!