The Wayback Machine - https://web.archive.org/web/20200914171640/https://github.com/chokcoco/iCSS/issues/23
Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CSS新特性contain,控制页面的重绘与重排 #23

Open
chokcoco opened this issue Aug 13, 2017 · 19 comments
Open

CSS新特性contain,控制页面的重绘与重排 #23

chokcoco opened this issue Aug 13, 2017 · 19 comments
Labels

Comments

@chokcoco
Copy link
Owner

@chokcoco chokcoco commented Aug 13, 2017

在介绍新的 CSS 属性 contain 之前,先简单介绍一下什么是页面的重绘与重排。

发现之前已经描述过很多次了,可以看看这个提高 CSS 动画性能的正确姿势

OK,下面进入本文正题,

contain 为何?

contain 属性允许我们指定特定的 DOM 元素和它的子元素,让它们能够独立于整个 DOM 树结构之外。目的是能够让浏览器有能力只对部分元素进行重绘、重排,而不必每次都针对整个页面。

The contain property allows an author to indicate that an element and 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 them for a limited area of the DOM and not the entire page.

contain 语法

看看它的语法:

{
  /* No layout containment. */
  contain: none;
  /* Turn on containment for layout, style, paint, and size. */
  contain: strict;
  /* Turn on containment for layout, style, and paint. */
  contain: content;
  /* 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;
}

除去 none,取值还有 6 个,我们一个一个来看看。

contain: size

contain: size: 设定了 contain: size 的元素的渲染不会受到其子元素内容的影响。

The value turns on size containment for the element. This ensures that the containing box can be laid out without needing to examine its descendants.

我开始看到这个定义也是一头雾水,光看定义很难明白到底是什么意思。还需实践一番:

假设我们有如下简单结构:

<div class="container">
   
</div>
.container {
    width: 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>')
})

那么会得到如下结果:

containsize

可以看到,容器 .container 的高度是会随着元素的增加而增加的,这是正常的现象。

此刻,我们给容器 .container 添加一个 contain: size,也就会出现上述说的:设定了 contain: size 的元素的渲染不会受到其子元素内容的影响

.container {
    width: 300px;
    padding: 10px;
    border: 1px solid red;
+   contain: size
}

再看看会发生什么:

containsize2

正常而言,父元素的高度会因为子元素的增多而被撑高,而现在,子元素的变化不再影响父元素的样式布局,这就是 contain: size 的作用。

contain: style

接下来再说说 contain: stylecontain: layoutcontain: paint。先看看 contain: style。

截止至本文书写的过程中,contain: style 暂时被移除了。

CSS Containment Module Level 1: Drop the at-risk “style containment” feature from this specification, move it Level 2。

嗯,官方说辞是因为存在某些风险,暂时被移除,可能在规范的第二版会重新定义吧,那这个属性也暂且放一放。

contain: paint

contain: paint:设定了 contain: paint 的元素即是设定了布局限制,也就是说告知 User Agent,此元素的子元素不会在此元素的边界之外被展示,因此,如果元素不在屏幕上或以其他方式设定为不可见,则还可以保证其后代不可见不被渲染。

This value turns on paint containment for the element. This ensures that the descendants of the containing box don’t display outside its bounds, so if an element is off-screen or otherwise not visible, its descendants are also guaranteed to be not visible.

这个稍微好理解一点,先来看第一个特性:

设定了 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 与没设定时会发生什么:

containsize3

CodePen Demo -- contain: paint Demo

设定了 contain: paint 的元素在屏幕之外时不会渲染绘制

通过使用 contain: paint, 如果元素处于屏幕外,那么用户代理就会忽略渲染这些元素,从而能更快的渲染其它内容。

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 测试的过程中(截止至2019/12/22,Chrome 78.0.3904.108),仅仅单独使用 contain:layout 并没有验证得到上述那么美好的结果。😅 😅

参考文献

@shellphon
Copy link

@shellphon shellphon commented Aug 13, 2017

没了?= =没懂

@chokcoco
Copy link
Owner Author

@chokcoco chokcoco commented Aug 14, 2017

@shellphon
啊,周末开了个头,还有内多内容,还没写完。。。我先把入口关了,抱歉哈~

@chokcoco chokcoco added the 原理 label Sep 26, 2017
@sunseekers
Copy link

@sunseekers sunseekers commented Oct 12, 2017

写一个实例会好很多

@forever-z-133
Copy link

@forever-z-133 forever-z-133 commented Dec 4, 2017

催更

@jawil
Copy link

@jawil jawil commented Dec 4, 2017

太监了?拖了好久了,催更催更😂

@Oyxiaoxi
Copy link

@Oyxiaoxi Oyxiaoxi commented Dec 15, 2017

没懂。求解释!

@ChinaBigPan
Copy link

@ChinaBigPan ChinaBigPan commented Apr 26, 2018

求补全这个文章,催更啦 @chokcoco

@baishusama
Copy link

@baishusama baishusama commented Oct 12, 2018

催更催更

@mask2012
Copy link

@mask2012 mask2012 commented Oct 12, 2018

在github上写博客就是好,一堆人给你催更,有没有动力满满~

@arcsin1
Copy link

@arcsin1 arcsin1 commented Jan 14, 2019

催更催更

1 similar comment
@MT-X
Copy link

@MT-X MT-X commented Mar 7, 2019

催更催更

@MeCKodo
Copy link

@MeCKodo MeCKodo commented Mar 27, 2019

吹更

@twosugar
Copy link

@twosugar twosugar commented May 16, 2019

催更

1 similar comment
@claviering
Copy link

@claviering claviering commented May 16, 2019

催更

@yuqi17
Copy link

@yuqi17 yuqi17 commented May 24, 2019

作者,我还是不明白到底有啥用,没有demo 代码呀,差评

@AMrainman
Copy link

@AMrainman AMrainman commented Dec 12, 2019

contain 可以用在所有元素上,是提升页面性能的属性。
contain 属性可以防止某个元素的 CSS 规则的改变影响页面上的其他东西。也就是说设置了contain: strict;的元素,其本身和子元素的发生重绘重排不会触发外部的元素的重绘重排。

@1998yyh
Copy link

@1998yyh 1998yyh commented Dec 16, 2019

包含
属性可以防止某个元素的CSS规则的改变影响页面上的其他东西。此设置了包含:strict;的元素,其本身和子元素。的发生重绘重排不会触发外部的元素的重绘重排。

那这么说就可以无脑堆这个属性了吗

@chokcoco
Copy link
Owner Author

@chokcoco chokcoco commented Dec 22, 2019

@1998yyh 不能无脑堆,会引起一些其他问题,譬如元素只绘制了一半(类似于 overflow hidden,部分内容超出了元素的边界)
然后我各种尝试发现这个属性没那么好掌握,很多怪异的表现。

@GaoJuqian
Copy link

@GaoJuqian GaoJuqian commented Aug 12, 2020

mark

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.