一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第27天,点击查看活动详情。
前情提要
说到前端渲染的性能问题时,除了网络层面的,就得从如何减少浏览器的重排和重绘说起了。其实对于浏览器的重排和重绘平时并没有多大的感知,无论你怎么写,好像都没有什么问题。直到我们项目组接手了一个全部由需求包开发的海外OA管理系统开始。项目挂到我们组进行维护和升级迭代,本来是交给组里的小姑娘,结果小姑娘搞不定,就只能派我上了。看了代码才发现,嗯...小姑娘看不懂可太正常了。具体的项目前端架构,组件拆分,逻辑书写的存在的问题就不一一细说了。只是每次启动项目,随便操作两下,就发现在浏览器的console面板上一次次的打印出浏览器强制重排重绘耗费xxxxms。然后不仅如此,还爆出了由此引发的页面渲染错误,偶尔还会出现卡死状态。所以,这让我不得不借着这个项目重新审视浏览器的重排和重绘问题。
首先先了解什么是重排和重绘?
其实重排和重绘就好比盖房子一样,重排就是设计师也就是浏览器根据具体的改动信息重新设计图纸上某些部分的最新位置。而重绘便是根据最新图纸进行打地基,浇筑水泥等将房子盖起来。
而在浏览器中,页面的渲染靠的就是一次又一次的重排和重绘。那什么时候会引发重排呢?
当DOM的某个节点发生几何式的变化便会触发一次重排。那什么是几何式的变化呢?就是当某个DOM节点的长,宽,边框的大小,外边距,和内边距,浮动了,采用了定位,并且位置发生了变化等都属于几何变化。
而重绘是指发生重排之后,对页面进行整体的重新绘制。除此之外,页面可能没有发生重排,可能只是某个节点的颜色发生了变化,那么此时也会触发一次重绘,重新绘制该DOM节点的颜色。
那么在实际开发中什么操作会引起重排呢?
- 页面渲染器初始化时
- 浏览器窗口尺寸发生变化
- 当浏览器出现滚动条时
- 当页面布局和几何属性发生变化时(几何属性包含:元素的位置,尺寸,内容)
- 添加或者删除肉眼可见的DOM元素
- js去查看dom元素的
offseTop, offsetLeft, offsetWidth, offsetHeight, scrollTop, scrollLeft, scrollWidth, scrollHeight, clientTop, clientLeft, clientWidth, clientHeight, getComputedStyle()时,
重排和重绘带来了什么影响呢?
答案很显然,每次的重排和重绘都会带来时间和浏览器的性能开销,会导致浏览器ui线程的卡顿。如果页面内容很少的情况下,可能这个优化做跟不做意义不大。但是当页面内容很多,像我们的海外OA那个项目里一个流程单里有九个表格,而在浏览器的布局计算中,表格会增加额外的计算时间。那么这个时候优化重排和重绘带来的影响就显得尤为重要了。
那么开发中如何才能让浏览器减少重排和重绘呢?
- 通过js进行DOM的操作或者DOM的css样式操作时,进行合并操作。
- 动态改变样式时,尽量使用动态更换className来实现
- 减少table布局
- 牺牲平滑度换取速度
- 不要经常访问会引起浏览器和重排和重绘的属性,如果确实要访问,就利用缓存进行访问。
- 让元素脱离动画流,减少render树的规模
- IE中避免使用javascript表达式
总结
- 重排又称回流
- 减少操作DOM就是减少触发重排
- 当使用DocumentFragment进行缓存,只触发一次重排和重绘
- 使用display:none。只引发两次重排和重绘
- 使用cloneNode(true of false)和replaceChild,只引发一次回流和重绘。