contain 属性
这个 contain 属性的主要目的是隔离指定内容的样式、布局和渲染。开发人员可以使用这个 contain 属性来限制指定的DOM元素和它的子元素同页面上其它内容的联系;我们可以把它看做一个iframe。跟iframe很相似,它能建立起一个边界,产生一个新的根布局;保证了它和它的子元素的DOM变化不会触发父元素重新布局、渲染等。
开发人员可以用这个 contain 属性声明一个元素和它的子元素是——尽可能的——和页面上的其它元素保持独立。— 来自 W3C 规范
contain 使用场景举例
我们已经知道了,使用这个 contain 属性可以将一个元素标志为和页面上其它元素是相对独立的元素。为了说明这个属性的作用,下面举几个使用例子:
页面小饰件(widgets)
通常在页面上添加第三方小饰件时,我们几乎对它们没有什么太多的控制,比如分享工具,它们可能会因为具有相当耗资源的布局、样式、渲染操作等大幅度的降低整个页面的执行效率。为了将它们同我们的网站隔离开来,使用 contain: strict; 将第三方的小饰件同页面上的其它内容隔离开来。
屏幕外的内容
如果你有一个导航栏或其它类似的东西并不在屏幕可现实范围内出现,浏览器同样会为这些不可见的元素进行渲染。通过使用 contain: paint; 浏览器就会忽略渲染这些屏幕外不可见的元素,从而能更快的渲染其它内容。
什么时候应该使用contain
如果你的页面很简单,没有复杂的DOM节点和小饰件(widgets),那就没必要考虑使用这种css的contain技术。而如果你开发的页面非常复杂,那么,这个css的contain技术可以帮助你优化页面的性能。而对于第三方的小饰件,始终使用contain: strict;是很好的习惯,它可以保护你的页面不受它们的干扰而出现性能问题。
contain 语法
看看它的语法:
{
/* No layout containment. */
contain: none;
/* Turn on size containment for an element. */
contain: size;
/* Turn on layout containment for an element. */
contain: layout;
/* Turn on style containment for an element. */
contain: style;
/* Turn on paint containment for an element. */
contain: paint;
/* Turn on containment for layout, paint, and size. */
contain: strict;
/* Turn on containment for layout, and paint. */
contain: content;
}
none | strict | layout | style | paint | size | contain
这个 contain 属性可以有7种不同的值。
- none 无
- layout 开启布局限制
- style 开启样式限制
- paint 开启渲染限制
- size 开启size限制
- content 开启除了size外的所有限制
- strict开启 layout, style 和 paint 三种限制组合
除去 none,取值还有 6 个,我们一个一个来看看。
contain: size
contain: size: 设定了 contain: size 的元素的渲染不会受到其子元素内容的影响。
我开始看到这个定义也是一头雾水,光看定义很难明白到底是什么意思。还需实践一番:
假设我们有如下简单结构:
<div class="container">
</div>
.container {
300px;
padding: 10px;
border: 1px solid red;
}
p {
border: 1px solid #333;
margin: 5px;
font-size: 14px;
}
并且,借助 jQuery 实现每次点击容器添加一个 <p>Coco</p> 结构:
$('.container').on('click', e => {
$('.container').append('<p>Coco</p>')
})
那么会得到如下结果:
可以看到,容器 .container 的高度是会随着元素的增加而增加的,这是正常的现象。
此刻,我们给容器 .container 添加一个 contain: size,也就会出现上述说的:设定了 contain: size 的元素的渲染不会受到其子元素内容的影响。
.container {
300px;
padding: 10px;
border: 1px solid red;
+ contain: size
}
再看看会发生什么:
正常而言,父元素的高度会因为子元素的增多而被撑高,而现在,子元素的变化不再影响父元素的样式布局,这就是 contain: size 的作用。
contain: style
接下来再说说 contain: style、contain: layout 、contain: paint。先看看 contain: style。
截止至本文书写的过程中,contain: style 暂时被移除了。
嗯,官方说辞是因为存在某些风险,暂时被移除,可能在规范的第二版会重新定义吧,那这个属性也暂且放一放。
contain: paint
contain: paint:设定了 contain: paint 的元素即是设定了布局限制,也就是说告知 User Agent,此元素的子元素不会在此元素的边界之外被展示,因此,如果元素不在屏幕上或以其他方式设定为不可见,则还可以保证其后代不可见不被渲染。
这个稍微好理解一点,先来看第一个特性:
设定了 contain: paint 的元素的子元素不会在此元素的边界之外被展示
设定了 contain: paint 的元素的子元素不会在此元素的边界之外被展示
这个特点有点类似与 overflow: hidden,也就是明确告知用户代理,子元素的内容不会超出元素的边界,所以超出部分无需渲染。
简单示例,假设元素结构如下:
<div class="container">
<p>Coco</p>
</div>
.container {
contain: paint;
border: 1px solid red;
}
p{
left: -100px;
}
我们来看看,设定了 contain: paint 与没设定时会发生什么:
设定了 contain: paint 的元素在屏幕之外时不会渲染绘制
通过使用 contain: paint, 如果元素处于屏幕外,那么用户代理就会忽略渲染这些元素,从而能更快的渲染其它内容。
https://www.98891.com/article-25-1.html
contain: layout
contain: layout:设定了 contain: layout 的元素即是设定了布局限制,也就是说告知 User Agent,此元素内部的样式变化不会引起元素外部的样式变化,反之亦然。
This value turns on layout containment for the element. This ensures that the containing box is totally opaque for layout purposes; nothing outside can affect its internal layout, and vice versa.
启用 contain: layout 可以潜在地将每一帧需要渲染的元素数量减少到少数,而不是重新渲染整个文档,从而为浏览器节省了大量不必要的工作,并显着提高了性能。
使用 contain:layout,开发人员可以指定对该元素任何后代的任何更改都不会影响任何外部元素的布局,反之亦然。
因此,浏览器仅计算内部元素的位置(如果对其进行了修改),而其余DOM保持不变。因此,这意味着帧渲染管道中的布局过程将加快。
存在的问题
描述很美好,但是在实际 Demo 测试的过程中(截止至2021/04/27,Chrome 90.0.4430.85),仅仅单独使用 contain:layout 并没有验证得到上述那么美好的结果。
设定了 contain: layout 的指定元素,改元素的任何后代的任何更改还是会影响任何外部元素的布局,点击红框会增加一条 <p>Coco<p> 元素插入到 container 中:
简单的代码如下:
<div class="container">
<p>Coco</p>
...
</div>
<div class="g-test"></div>
html,
body {
100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
gap: 10px;
}
.container {
150px;
padding: 10px;
contain: layout;
border: 1px solid red;
}
.g-test {
150px;
height: 150px;
border: 1px solid green;
}
目前看来,contain: layout 的实际作用不那么明显,更多的关于它的用法,你可以再看看这篇文章:CSS-tricks - contain
contain: strict | contain: content
这两个属性稍微有点特殊,效果是上述介绍的几个属性的聚合效果:
contain: strict:同时开启 layout、style、paint 以及 size 的功能,它相当于 contain: size layout paint
contain: content:同时开启 layout、style 以及 paint 的功能,它相当于 contain: layout paint
所以,这里也提一下,contain 属性是可以同时定义几个的。
Can i Use -- CSS Contain
截止至 2021-04-27,Can i Use 上的 CSS Contain 兼容性,已经可以开始使用起来: