js中的回流和重绘

230 阅读3分钟

浏览器的渲染过程

  • 浏览器的渲染过程主要包括以下几步:
    • 解析HTML生成DOM树。
    • 解析CSS生成CSSOM规则树。
    • 将DOM树与CSSOM规则树合并在一起生成渲染树。
    • 遍历渲染树开始布局,计算每个节点的位置大小信息。
    • 将渲染树每个节点绘制到屏幕。

渲染阻塞

当浏览器遇到一个 script 标记时,DOM 构建将暂停,直至脚本完成执行,然后继续构建DOM。每次去执行JavaScript脚本都会严重地阻塞DOM树的构建,如果JavaScript脚本还操作了CSSOM,而正好这个CSSOM还没有下载和构建,浏览器甚至会延迟脚本执行和构建DOM,直至完成其CSSOM的下载和构建。

所以,script 标签的位置很重要。实际使用时,可以遵循下面两个原则:

    · CSS 优先:引入顺序上,CSS 资源先于 JavaScript 资源。

    · JS置后:我们通常把JS代码放到页面底部,且JavaScript 应尽量少影响 DOM 的构建。

回流

回流当render tree中的一部分或全部因为元素的规模尺寸、布局、隐藏等改变时,浏览器重新渲染部分DOM或全部DOM的过程。回流也被称为重排,其实从字面上来看,重排更容易让人形象易懂(即重新排版整个页面)。

重绘

当页面元素样式改变不影响元素在文档流中的位置时(如background-color,border-color,visibility),浏览器只会将新样式赋予元素并进行重新绘制操作。

什么时候会触发回流或重绘?

有大量的用户行为以及潜在的DHTML改变会触发回流。例如,改变浏览器窗口的大小,使用一些JavaScript方法,包括计算样式,对DOM进行元素的添加或删除,或是改变元素的class等。

添加或者删除可见的DOM元素;

元素位置改变;

元素尺寸改变——边距、填充、边框、宽度和高度;

内容变化,比如用户在input框中输入文字,文本或者图片大小改变而引起的计算值宽度和高度改变;

页面渲染初始化;

浏览器窗口尺寸改变,resize事件发生时;

计算offsetWidth和offsetHeight属性;

设置style属性的值;

回流必将引起重绘,而重绘不一定会引起回流。

如何减少回流、重绘?

  • CSS中避免回流、重绘

    • 尽可能在DOM树的最末端改变class
    • 避免设置多层内联样式
    • 动画效果应用到position属性为absolute或fixed的元素上
    • 避免使用table布局
    • 使用css3硬件加速,可以让transform、opacity、filters等动画效果不会引起回流重绘
  • JS操作避免回流、重绘

    • 避免使用JS一个样式修改完接着改下一个样式,最好一次性更改CSS样式,或者将样式列表定义为class的名称
    • 避免频繁操作DOM,使用文档片段创建一个子树,然后再拷贝到文档中
    • 先隐藏元素,进行修改后再显示该元素,因为display:none上的DOM操作不会引发回流和重绘
    • 避免循环读取offsetLeft等属性,在循环之前把它们存起来
    • 对于复杂动画效果,使用绝对定位让其脱离文档流,否则会引起父元素及后续元素大量的回流

总结

回流在浏览器中属于一种用户主导的操作,所以知道如何去改进回流时间以及知道各种文档属性(DOM节点深度,css的渲染效率,各种各样的样式改变)对回流时间的影响对于前端开发来讲是很有帮助的。有时即便是回流一个单一的元素,也可能要求它的父元素以及任何跟随它的元素也产生回流。例如需要改变某个元素的背景,这就不涉及该元素的属性,所以只发生重绘。