CSS的书写顺序对性能的影响你知道么?

4,732 阅读5分钟

之前看过这样一篇文章:

先来看一段代码

width: 150px;
height: 150px;
font-size: 24px;
position: absolute;

当浏览器解析到position的时候,发现该元素是绝对定位,需要脱离文档流,但是之前的属性都是按照常规解析的,所以不得不重新渲染,这时渲染引擎就系要接触该元素再文档中的占位,这样就有可能导致其他元素受到他的回流影响进而发生重排。

调整后代码

position: absolute;
width: 150px;
height: 150px;
font-size: 24px;

根本原因: reflow(回流)

其实是该元素回流导致,减少浏览器reflow(回流),就可以提升浏览器渲染dom的性能

那么问题来了?到底怎样才可以减少reflow(回流)呢?

要尽量避免,那就需要知道浏览器的渲染过程!

  1. 解析html构建dom树,解析css构建css树:将html解析成树形的数据结构,将css解析成树形的数据结构
  2. 构建生成render树:DOM树和CSS树合并之后形成的render树。
  3. 排版布局render树:有了render树,浏览器已经知道那些网页中有哪些节点,各个节点的css定义和以及它们的从属关系,从而计算出每个节点在屏幕中的位置。
  4. 绘制渲染render树:按照计算出来的规则,通过显卡把内容画在屏幕上。

css代码从解析到显示到浏览器屏幕上,其实就是上面的2->3->4的过程。

  • 浏览器并不是一获取到css样式就立即解析,而是根据css样式的书写顺序,将其对应dom树的结构而分布render样式,与DOM树合并完成并生成render树,也就是上面的第2步。
  • 然后遍历render树每个结点的css样式进行解析,此时的css样式的遍历顺序完全是按照之前的书写顺序。在解析过程中,一旦浏览器发现某个元素的定位变化影响布局,则需要倒回去重新渲染。就会导致第3步占用的时间过长,直接影响到了第4步的显示。

这里有一个规范,建议顺序大致如下:

1、定位属性:

position、display、float、left、top、right、bottom、overflow、clear、z-index

2、自身属性:

width、height、padding、border、margin、background

3、文字样式:

font-family、font-size、font-style、font-weight、font-varient、color

4、文本属性:

text-align、vertical-align、text-wrap、text-transform、text-indent、text-decoration、letter-spacing、word-spacing、white-space、text-overflow

5、CSS3 中新增属性:

content、box-shadow、border-radius、transform

减少reflow对性能的影响的建议

  1. 不要一条一条地修改 DOM 的样式,预先定义好 class,然后修改 DOM 的 className
  2. 把 DOM 离线后修改,比如:先把 DOM 给 display:none (有一次 Reflow),然后你修改100次,然后再把它显示出来
  3. 不要把 DOM 结点的属性值放在一个循环里当成循环里的变量
  4. 尽可能不要修改影响范围比较大的 DOM
  5. 为动画的元素使用绝对定位 absolute / fixed
  6. 不要使用 table 布局,可能很小的一个小改动会造成整个 table 的重新布局

PS:对于是否是真的会影响性能,下面做一个实验。\color{FF0000}{PS:对于是否是真的会影响性能,下面做一个实验。}

扩展

repaint(重绘)

是指一个元素外观的改变所触发的浏览器行为,浏览器会根据元素的新属性重新绘制,使元素呈现新的外观。这个过程就是重绘。重排必定会引发重绘,但重绘不一定会引发重排

常见引发重绘的属性

color、border-style、visibility、background、text-decoration、background-image、background-position、background-repeat、outline-color、outline、outline-style、border-radius、outline-width、box-shadow、background-size

减少repaint对性能的影响的建议

  1. 不要一条一条地修改 DOM 的样式。可以先定义好 css 的 class,然后修改 DOM 的 className。
  2. 不要把 DOM 结点的属性值放在一个循环里当成循环里的变量。
  3. 为动画的 HTML 元件使用 fixed 或 absoult 的 position,那么修改他们的 CSS 是不会 reflow 的。
  4. 千万不要使用 table 布局。因为可能很小的一个小改动会造成整个 table 的重新布局。(table及其内部元素除外,它可能需要多次计算才能确定好其在渲染树中节点的属性,通常要花2~3倍于同等元素的时间。这也是为什么我们要避免使用table做布局的一个原因。)
  5. 不要在布局信息改变的时候做查询(会导致渲染队列强制刷新)
  6. 用translate替代top改变
  7. 用opacity替代visibility(在独立图层下优化重绘)

实验

这是一个消防工程师广告的项目的一个页面,页面布局太简单的话,可能看不出差距

p标签的position属性后定义!

p标签的position 先定义

结果:\color{FF0000}{结果:}

测试了30次左右,再项目中的css用的较多的情况下(故意多谢一些css,为了让css更多) 用chrome的调试工具的perfomancs项还是有点细微的区别,大体上是:直接表现是css计算时间减少了一点,但是paint时间竟然增加了!!!,

结论:\color{FF0000}{结论:}

貌似对css的计算是有些许影响,但是最终浏览器的总时间并没有太大出入(多次的平均值)\color{FF0000}{貌似对css的计算是有些许影响,但是最终浏览器的总时间并没有太大出入(多次的平均值)。}

PS:记得chrome有一个timline选项的,但是找不到了,不知道是不是版本的原因,这次试用perfomancs项测试的,后续有机会用timline重新搞一次。本次测试是在mac下测试的(大约做了30次左右的对比),只电脑只开了一个chrome窗口和微信(截图用了),以防其他的应用影响。都是perfomancs自动录制了5s的数据,更改属性位置后记得清掉缓存。有兴趣的小伙伴可以自行实验。欢迎大神指正!!!