【译】Chrome 52 中的 CSS Containment 属性

译自:https://developers.google.com/web/updates/2016/06/css-containment?hl=en

摘要

新的 CSS Containment 属性让开发者控制浏览器的样式、布局、重绘的工作区域。

containment.jpg

这个属性有一些可选值,语法是这样:

contain: none | strict | [ 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

contain 属性

CSS Containment 是一个新的属性,关键字 contain,支持 4 个可选值:

  1. layout
  2. paint
  3. size
  4. style

每个值都允许你控制浏览器需要做多少渲染工作量。 让我们详细的看看每个值。

布局 (contain: layout)

这个值给元素开启布局控制。 它确保被控制的元素对于布局用途是完全不透明的; 外部的任何东西都不会影响它内部的布局,反过来也一样。 Containment 规范

布局控制可能是最有用的,与contain: paint一样。

布局通常是文档作用域的,导致它会扩散到整个 DOM 大小。 如果你改变了一个元素的 left 属性(如此所说),文档中的每一个 DOM 元素(的位置)可能都得被检查一遍。

在这里启用 containment 属性可以潜在地减少(影响的)数量到个别元素,而非整个文档;从而减少浏览器的大量无用功,显著提升浏览器性能。

重绘(contain: paint)

这个值给元素开启重绘控制。 它确保被控制元素的子元素不会显示到它的边框之外。 所以如果一个元素在屏幕外或者某些原因不可见,它的子元素也被担保不可见。 Containment 规范

重绘控制是另一个非常有用的控制。 重绘控制大体上就是把这个元素单独“切”出来,而且它还有一些其他副作用:

  • 它对绝对定位(absolute)和固定定位(fixed)的元素起一个控制块的作用。 这意味着其任何子元素都是基于这个元素定位的,而不是基于其他元素比如 document。

  • 它变为一个层叠上下文(stacking context)。 这意味着像 z-index 这类属性会对这个元素起作用,它的子元素会基于新的上下文层叠。

  • 它变为一个新的格式化上下文(formatting context)。 这意味着如果你有——例如——一个启用重绘控制的块级元素,它会被视作一个新的,独立的布局环境。 换句话说,外面元素的布局不会影响被控制元素的子元素。

大小(contain: size)

这个值给元素开启大小控制。 它确保被控制元素的大小计算无需考虑其子元素。 Containment 规范

contain: size 的意思是子元素不影响其父元素的大小,而直接用显式定义的尺寸。 因此如果你设置了 contain: size 却没指定元素的尺寸(直接设置或通过 flex 属性),它会被渲染为 0*0!

大小控制的确是一个谨慎的做法,确保你不依赖其子元素计算大小,但它对性能影响并不是很大。

样式(contain: style)

这个值给元素开启样式控制。 它确保那些可能会对其他元素或者他的子元素产生影响的样式的效果不会逃出被控制的元素之外。 Containment 规范

改变其中一个元素的样式到底会对整个 DOM 树有什么影响,这种事情很难预言。 一个简单的例子是 CSS 计数器,其中一个子元素的计数就能影响整个文档中其他相同名称的计数值。 如果设置了 contain: style,样式的改变不会传播到被控制元素之外。

讲得清楚一些,contain: style 不能像影子 DOM 那样控制样式表的作用域。 这里的控制只是单纯的限制当样式改变时对其他 DOM 树部分的影响,与样式定义无关。

严格和内容控制

你还能组合这些关键字,例如 contain: layout paint,可以给元素同时应用多种行为。 contain 还另外支持两个附加值:

  • contain: strict:等同于 contain: layout style paint size
  • contain: content: 等同于 contain: layout style paint

当你预先知道元素的大小(或者想预先保留元素尺寸)的时候,使用严格控制(contain: strict)很好。 但千万记得,如果你设置了严格控制但没给元素指定大小,由于其隐式的 contain: size,元素会被渲染为 0*0 的块。

另一方面,“内容控制”可提供显著的作用域改善,但不需要你事先知道或者指定元素的尺寸。

这两个值里面,contain: content 是你应该默认优先考虑的。 当 contain: content 不能满足你的需要时再考虑 contain: strict

让我们知道你与它相处的怎么样

Containment 是一种给浏览器指出在你的页面里你想要把那些东西孤立出来的好方法。
在 Chrome 52+ 里尝试一下,让我们知道你与它相处的如何。