reflow(回流)与repaint(重绘)的区别及优化
1.回流及重绘的概念
回流(reflow):当render tree中的元素的宽高、布局、显示、隐藏或元素内部文字结结构发生改变时,会影响自身及其父元素、甚至追溯到更多的祖先元素发生改变,则会导致元素内部、周围甚至整个页面的重新渲染,页面发生重构,回流就产生了。
重绘(repaint):元素的结构(宽高、布局、显示隐藏、内部文字大小)未发生改变,只是元素的外观样式发生改变,比如背景颜色、内部文字颜色、边框颜色等。此时会引起浏览器重绘,显然重绘的速度快于回流。
回流一定会触发重绘,重绘不一定触发回流。
2.回流重绘对性能的影响
这里了解一个知识点:渲染css样式会影响js执行的时间,使得加载js脚本变慢。原因如下:
浏览器渲染一个网页的时候会启用两条线程:一条渲染javascript 脚本,另一条渲染 ui 即css 样式的渲染。但这两条线程是互斥的,当javascript 线程运行的时候 ui 线程则会中止暂停,反之亦然。因为当ui 线程运行对页面进行渲染的时候, js 脚本难免会涉及到页面视图上的一些样式的改变,为了使这个改变更加准确 js 脚本只好等待ui 线程渲染完成的时候才去执行。
所以当一个页面的元素样式改动频繁的时候ui 线程就会持续渲染,造成js 代码反应慢半拍,卡顿的情况。回流和重绘都会使得ui线程渲染时间加长,太多就会使得网站性能变差,因此要尽量减少reflow和repaint。
3.如何减少回流和重绘
导致回流发生的情况如下:
- 改变窗口大小
- 改变文字大小
- 内容的改变,如用户在输入框中敲字
- 激活伪类,如:hover
- 操作class属性
- 脚本操作DOM
- 计算offsetWidth和offsetHeight
- 设置style属性
对应的css属性如下:
- 盒子模型相关属性
- 定位及浮动属性
- 节点内部的文字结构
导致重绘的css属性如下:
减少回流和重绘注意点如下:
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 加速,但是不能滥用 |
相关参考: