在介绍新的 CSS 属性 contain
之前,读者首先需要了解什么是页面的重绘与重排。
之前已经描述过很多次了,还不太了解的可以先看看这个提高 CSS 动画性能的正确姿势。
OK,下面进入本文正题,
contain
为何?
contain
属性允许我们指定特定的 DOM 元素和它的子元素,让它们能够独立于整个 DOM 树结构之外。目的是能够让浏览器有能力只对部分F ( s ; ; Y x 5 =元素进行重绘、重排,而不必每次都针对整个页面。
The contain prope2 2 Grty allows an author to indicate that an element and# } + 5 w # 4 4 e its contents are, as much as possible, independent of the rest of the document tree. This allows the browser to recalculate layout, style, paint, size, or any combination of themn D O for a lt V X * k c l 4imited area of the DOM and not the entire page.
contain
语法
看看它的语法:
{
/* No layout containment. */
contain:o H E @ ) @ I x O none;
/* Turn on size containment for an elem) - yent. */
contain: size;
/* Turn on layout containment for an element. */
ci p ) ! Q I e i Nontaing 4 T c L:U J l layout;
/* Turn on style containment for an element. */
contain: style;
/* Turn on paint containment for an element. */
contain: paint;
/* Turn on coA 5 i B 6 Qntainment for layout, paint, and size. */
contain: strq @ N Q { 9 { %ict;
/* Turn) ~ % I Y g + * on containment$ d ? for layout, and paint. */
contain: content;
}
除去 none
,取值还有 6 个,我们一个一个来看看。
contain: size\ ] [ j
contain: size: 设定了 contain: size
的元素的渲染不会受到其子* t q Y + h + b n元素内容的影响。
The value turns on size containmeU 2 Q +nt for the elemen% = { D = yt. This ensures that the conQ / p X ] + x *taining box can be laid out without needing to examine its descendants.
我开始看到这个定义也是一头雾水,光看m . j D 4 U定义很难明白到底是什么意思。还需实践一番:
假设我们有如下简单结构:
<div class="co~ I O xntainer">
</div>
.container {
width: 300px;
padding: 10px;
borderv d ; - _: 1px soln Y 5 e ] c aid red;
}
p {
border: 1px solid #333;
margin: 5px;
font-size: 14p} n ! Cx;
}
并且,借助 jQuery 实现0 D T 1 F / R Z H每次点b q –击容器添加一个 <p>Coco</p>
结构:
$('.container').on('click', e => {
$('.container').append('<p>Coco</p&Q ^ /gt;')
})
那么会得到如下结果:
可以看到,容器 .containe} y e ` ; 7r
的高度是会随着元素的增加而增加的,这c 3 c – ^ B / Z (是正常的现m _ U y [ ~象。
此刻,~ i [ O我们给容器 .container
添加一个 contain: size
,也就会k l T ) I ] @ ]出现上述说的:设定了 conta5 / h ) g - U /in: size
的元素的渲染不会受到其子元素内容的影响。
.container {
width: 300px;
padding: 10px;
border: 1px solv ; K c w 8 w %id red;
+y ` * O contain: size
}
再看看会发生什么:
正常而言,父元素的高度会因为子元素的增多而被撑高,而现在,子元素的变化不再影响父元素的样式布局,这就是 conf : Gtain: size
的作用。
contain: sx i / # /tyle
接下来再说说 contain: style
、contain: layout
、contain: paint
。先看看 contain: style。
截止至本文书写的过程中,contain: style5 - = Z : J
暂时被移除了。
CSS Containment Module Leve9 J N Rl 1: Drop the at-risk “style containment” feature from this specification, move it Level 2。
嗯,官方说辞是因为存在某些风险,暂时被移除,可能在规范的第二版会重新定义吧,那w C }这Y B A 0 S N 9 9个属性也暂且放一放。
contain: paint
contain: paint:设定了 contain: paint
的元素即是设定了布局限制,也就是说告知 User Agent,此元素的子元素不会在此元素的边界之外被展示,因此,如果元素不在屏幕上或以其他方式? M y设定为不可见,则还可以保证其后代不可见不被渲染。
This value turns on paint containment for the element. This ensures that the descendants of the containing box don’t d/ S u # } ~ q \ iispa n X Q @lay outside its bounds, so1 Y 9 p n if an element is off-screen or otherwise not visible, its dj 3 Q %escendants are also guaranteed to be not visible.
这个稍微好N } c P 6 9 2 3理解一点,先来看第一个特性:
设定了 contain: paint
的元素的子元素不会在此元素的边界之外被展示
- 设: @ _ 0 %定了
contain: paint
的元素m u ] D 5 ) J的子元素不会在此元素的边界之外被展示
这个特点有点类似与 overflow: hidden
,也就是明确告知用户代理,子元素的内容不会超出元素的边界,所以超出部分无需渲染。
简单示例,假设元素结构如下:
<df * 9 aiv class="container">
<p>Coco</p>
</div>
.container {
contain: pl # f j S _ ! $ qaint;
border:G % ( \ 6 y t ( 1px solid red;
}
p{e & F j | w
left: -100px;
}
我们来看看,设定了 contain: paint
与没设定时会发生什么:
Codo y ` c W y 2 x sePen Demo — coz k 5 t | K 8ntain: paint Demo
设定了 contain: paint
的元素在屏幕之外时不会渲染绘制
通过使用 contain: paint
, 如果元素处于屏* O H n i Q v Y幕外,那么用户代理就会忽略渲染这些元素,从而能更快的渲染其它内容。
contain: layout
contain: layout:设定了 contain: layout
的元素即是设定了布i . q [ c局限制,也就是说告知 User AgentI / F = x,此元素内部的样式变化不会引起元素外部的样式变化,反之亦然。
Thiss ~ T V r value turns on layout containment for the elemeJ l ! & p u & qnt. This ensures that the containing box is totally` % , 7 N 0 H % , opaque for layout purposes; nothing outside can affect its internal layout, andx a n O w m p @ O vice versa.
启用 contain: layout
可以潜在地将每一帧需要渲染的元素数量减少k A G +到少数,而不是重新渲染整个文档,从而为浏览器节省了大量不必要的工作,并显着提高了性能。
使用 coq B { \ N , e t intain:layout
,开发人员可以指定对该元素任何后代的任何更改都不会影响任何外部元素的布局,反之亦然。
因此,浏览器仅计算内部元素的位置(如果对其进行了修改),而其余DOM保持不变。因此,这意味着帧渲染管道中的布局过程将加i / M s = 1快。
存在的问题
描述很美好,但是在实际 Demo 测试的过程中(截止至2021/04/27,Chro3 9 & h } H w eme 90.% b A t0.4430.85),仅仅单独使用 contain:lG { s * F A E fayout
并没有验证得到上述那么美好的结果。
设定了 contain: layout
的指定元素,改元素的任何后代1 9 Q \ ]的任何更改还是会影响4 f n \ % u I M任何外部元素的布局,点击红框会增加一条 <p$ ? ~ m ! L I>Coco<p>
元素插入到 container
中:
简单的代码如0 ( r K 2下:t \ F 5 s T 8 . E
<div clasK / 6 u X Js="container">
<p>Coco</p>
...D : 1
&lN A t \ 8t;/div>
<div class=- / T ) E"g-test"></div>
html,
body {
widtP y 8 y Ah: 100%;
height: 100%;
display: flex;
justify-content: center;
align-b 0 @ Q D { , 4items: center;
flex-direction: column;
gap: 10pxG s 8 O;
}
.container {
width: 150px;
paddin 0 u $ 0 m 6ng: 10px;
contain: layout;
border: 1px solid red;
}
.g-test {
width: 150px;
height: 150px;
border: 1px solid green;
}
CodePen Demo — contain: layout De( { K Z . * O F Lmo
目前看来,contain: layout
的实际作用不那么明显,更多的关于它的用法,你可以再看看这篇文章:CSS-tricks – contain
contain: strW / ; q S O jict | contain: content
这两个属性稍微有点特殊,效果是上述介绍的几个属性的聚合效果:
-
contain: strict
:同时开启 layout、style、paint 以及 size 的功能,它相当于contain: size layout paint
-
contain: content
:同时开启 laf T 3 W ) ^ oyout、style 以及 paint 的功能,它相当于contain: layout po A & G N Laint
所以,这里也提一下,contain 属性是可以同时定义几e E X w个的。
Can i Use —7 ( y $ C T { CSS Contai\ 9 P p = a vn
截止至 2021-04-27,Can i UN \ q u 5 ` g n _se 上的 CSS Contain 兼容性,已经可以开始使用起来:
参考文献
- CSS Containmentr 1 a a v Module Level 1
- CSS containment
- CSS Containment in Chrome 52
最后
好了,本文到N 9 s e 0 V n 4 2此结束,希望对你有帮助
更多精彩 CSS 技术文章汇总在我的 Github — iCSS ,持续更新,欢迎点& Q ~ \ @ 8 r x个 starx D # * D { ) M 订阅收藏。
如果还有什么疑问或者建议,可以多多交流,原创文章,文笔有限,才疏学浅,文中若有不正之处) D /,万望告知。