之前看了浏览器渲染原理,我的博客里有写,对于 repair 和 repaint 还是没有一个更深的概念。 最近又被diss 一波:
浏览器性能优化涉及到哪些?随意说了几个,对面又抛出问题,重绘( repaint ) 和 回流 ( reflow ) 哪个消耗性能高。
之前浏览器渲染机制里面我们提到过,repaint( 重绘 ) 和 reflow(回流),实际上了是 reflow 也就是 回流能耗高, repair(重绘)不一定触发回流,但是回流(reflow)一定会触发触发重绘(repair)
回到他的那篇课程的博客,'css会影响javascript 执行时间导致javascript 脚本变慢'。
它说,浏览器渲染网页的时候会启用俩条进程:一条渲染javascript脚本,另一条渲染ui即css样式的渲染。但是这俩条线程是互斥的。当JavaScript线程运行的时候ui线程则会终止暂停,反之亦然。
原因是,当ui线程运行对页面进行渲染的时候js脚本难免会涉及到页面视图样式的一些改变,为了使这个改变更加准确js只好等待ui线程渲染完成的时候才去执行。
所以当一个页面的元素样式改动频繁的时候ui线程就会持续渲染,造成js代码 反应慢半拍,卡顿的情况。
那回流 和 重绘究竟是什么,它们哪个威力比较大呢。
回流: 当render tree 的 一部分或全部的元素因改变了自身的宽高,布局,显示或隐藏,或者元素内部的文字结构发生变化 导致 需要重新构建页面的时候, 回流就产生了。
重绘:当一个元素自身的宽高,布局,及显示或隐藏没有改变,而只是改变了元素的外观风格的时候,就会产生重绘。例如你改变了元素的background-color...
因此我们得到一个结论:
回流必定触发重绘,而重绘不一定触发回流
配合上一篇文章浏览器渲染原理来看
触发回流的css 属性有这些:

而触发重绘的有这些:

现在我们知道了那些属性会触发回流,但是如何避免回流呢。
其实有两个方法:1,不使用以上能触发图层回流的属性。 2,建立一个图层,让回流在这些图层里面进行,限制回流和重绘的范围,减少浏览器的运算工作量。( 这里 说到图层,其实在说句难听的吧,以浏览器现在的性能只要自己不作死,浏览器不可能自己死。算了这里还需要图层写法,有空在提交一波 )
先说图层
css 中有一个重要的概念就是'划分图层'。
在页面加载完dom 之后,浏览器会根据自身制定的一些特殊css 属性 对页面进行划分。🌰:position:absolute 属性的元素他们会被浏览器归纳到一个图层中,而另外的一些position:fixed 的元素也会被浏览器归纳到另外一个图层中。还有一些例如: transform: tanslateZ(0) ... 这些属性都是视 浏览器厂商制定的。
图层的优点就是:当一个元素在自己图层内发生变化的时候它的回流 和 重绘只会发生在图层内部,从而减少了浏览器对于重绘与回流的运算量。
首先,图层对图层里面的节点做回流和重布局运算,计算出他们的样式。然后,对它们生成图形和位置,
紧接着,将每个节点绘制填充到图层位图中,
再然后,图层作为纹理发送到GPU 上
最后,将图层合并,显示在浏览器页面上
图层虽好,但是如果滥用图层的话就会让页面因为进行了太多合并运算而造成卡顿。
所以说,图层的用途应该让给那些经常要进行位置结构,布局变换的元素使用,例如轮播图。
创建图层
拿chome 来说,创建图层要满足以下其中一个条件:
1.一个dom元素拥有3d 或 透视变换的css 属性( persepective, transform )
video 标签
拥有3d 上下文 或者加速 2d 上下文的 canvas 节点
混合插件 flash
自己做的opacity 动画 或 使用 一个动画 webkit 变换的元素
拥有 translate3d 或 translateZ 这两会使 GPU 加速的属性
一个包含复合层子节点的元素。( 解释:举例就是本身整个网页页面就是一个图层,html 标签下包含着若干的标签head,body,... 这样就满足条件了 )
元素有一个其 z-index 比它低的兄弟节点。由于z-index 控制的是元素上下层的关系,所以当上下层关系变换的时候就需要一个图层就渲染,因此满足这个条件的元素也会被创建一个图层。
那 可替换属性优化性能和重绘,一共9点:
1: 用transform 代替top, left, margin-top, margin-left... 这些位移属性
2: 用opacity 代替 visibility, 但是要同时有translate3d 或 translateZ 这些可以创建的图层的属性存在才可以阻止回流
但是 第二点经过我的实验,发现如果不加 transform: translateZ(0) 配合opacity 的话 还是会产生回流的,而只用visibility 就只会产生重绘不会回流
而 opacity 加上 transform: translateZ/3d 这个属性之后便不会发生回流和重绘了
3:不要使用JS 代码对dom元素设置多条样式,选择使用一个className 代替之。
4:如果确实需要js 对dom 设置多条样式那么可以将这个dom先隐藏,然后对其设置
5:不要在循环内获取dom的样式例如: offsetWidth, offsetHeight, clientWidth, clientHeight...这些。浏览器有一个回流缓冲机制,即多个回流保存在一个栈里面,当这个栈满了浏览器便会一次性触发所有样式的更改且刷新这个栈,但是如果你多次获取这些元素的实际样式,浏览器为了给你一个准确的答案便会不停刷新这个缓冲栈,到这页面回流增加。
6:不要使用table布局,因为table的每一行甚至每一个单元格的样式更新都会导致整个table重新布局
7:动画的速度按照业务按需决定
8:对于频繁变化的元素应该为其加一个transform 属性,对于视频使用video 标签
9:必要时可以开启GPU加速,但是不能滥用
说到了图层,也就是会遇到 BFC
BFC 块级 格式化上下文,一旦形成一个块级格式化上下文,这个上下文中的元素的布局不会影响外部元素的布局
如何触发块级格式化上下文(常见)
1.根元素本身就会形成一个块级格式化上下文
2.overflow不为visible的
3.float不为none
4.inline-block 行内块元素
5.定位元素(position 是 absolute 或者 fixed)
6.flex 和 grid 布局
7.display 和 table 相关的,比如table, table-cell 等
例如这篇
https://www.cnblogs.com/lhb25/p/inside-block-formatting-ontext.html
文章引用
https://www.cnblogs.com/stitchgogo/p/7920828.html
文章采用 知识共享署名 4.0 国际许可协议 进行许可,转载时请注明原文链接。