1.总结
reflow(回流):对DOM树进行渲染,只要修改DOM或修改元素的形状大小,就会触发reflow。
display显示/隐藏元素,显示时占据空间,隐藏时元素不占据空间,隐藏前后dom结构有发生变化,需要重新渲染。
visibility显示/隐藏元素,显示时占据空间,隐藏时元素占据空间,隐藏前后dom结构未发生变化,不需要重新渲染。
单纯改变字体颜色,背景只需要repaint(重绘),不需要reflow。
会导致回流的操作:
1.页面首次渲染
2.浏览器窗口大小发生改变
3.元素尺寸或位置发生改变
4.元素内容变化(文字数量或图片大小等等)
5.元素字体大小变化
6.添加或者删除可见的DOM元素
7.激活CSS伪类(例如::hover)
8.查询某些属性或调用某些方法
1.我们首先讲讲HTML渲染过程
内容解释
1.HTML parser:HTML解析器,其本质是将HTML文本解释成DOM tree。
2.CSS parser:CSS解析器,其本质是讲DOM中各元素对象加入样式信息。
3.JavaScript引擎:专门处理JavaScript脚本的虚拟机,其本质是解析JS代码并且把逻辑(HTML和CSS的操作)应用到布局中,从而按程序要的要求呈现相应的结果
4.DOM tree:文档对象模型树,也就是浏览器通过HTMLparser解析HTML页面生成的HTML树状结构以及相应的接口。
5.render tree:渲染树,也就是浏览器引擎通过DOM Tree和CSS Rule Tree构建出来的一个树状结构,和dom tree不一样的是,它只有要最终呈现出来的内容,像或者带有display:none的节点是不存在render tree中的。
6.layout:也叫reflow 重排,渲染中的一种行为。当rendertree中任一节点的几何尺寸发生改变了,render tree都会重新布局。
7.repaint:重绘,渲染中的一种行为。render tree中任一元素样式属性(几何尺寸没改变)发生改变了,render tree都会重新画,比如字体颜色、背景等变化。
解析HTML并构建DOM树,DOM 树包含了所有的 html 标签,包括不展示的 head 节点和 display:none 的节点,还有用JS动态添加的元素等。
CSS标记则转换成CSS对象模型(CSSOM),CSSOM 树则会去掉浏览器不能识别的样式,比如不支持的浏览器前缀(chrome不支持的-moz-前缀)和 hack(如firefox不支持_开头的样式)。
将 DOM 树和 CSSOM 树合并为 render 树,在这个过程中,需要计算每一个呈现对象的可视化属性,会去掉不展示在页面上的节点(如 display:none 和 head 节点等),因为这些节点不会用于呈现,而且不会影响呈现的,所以就不会包含到render tree中,但是visibility:hidden隐藏的元素还是会包含到render tree中的,因为visibility:hidden 会影响布局(layout),会占有空间。
DOM Tree 和样式结构体组合后构建render tree, render tree类似于DOM tree,但区别很大,因为render tree能识别样式,render tree中每个NODE都有自己的style,而且render tree不包含隐藏的节点(比如display:none的节点,还有head节点),因为这些节点不会用于呈现,而且不会影响呈现的,所以就不会包含到 render tree中。
然后是布局 render 树。render 树在创建完成时,并不包含位置和大小信息。计算这些值的过程称为布局或重排。从 render 树的根节点((对应于 HTML 文档的 元素))递归调用,计算每一个元素的位置和大小信息。
最后使用 render 树绘制页面。在绘制阶段,系统会遍历 render 树,将其内容显示在屏幕上。
3.那什么是回流?什么又是重绘呢?
回流(Reflow):render 树中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建。回流的时候,浏览器会使渲染树中受到影响的部分失效,并重新构造这部分渲染树,完成回流后,浏览器会重新绘制受影响的部分到屏幕中,该过程称为重绘。
重绘:render tree中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不会影响 render 树重新布局的,比如修改字体颜色。
他们的区别很大:
1.回流必将引起重绘,而重绘不一定会引起回流。比如:只有颜色改变的时候就只会发生重绘而不会引起回流。
2.当页面布局和几何属性改变时就需要回流,比如:添加或者删除可见的DOM元素,元素位置改变,元素尺寸改变——边距、填充、边框、宽度和高度,内容改变。
回流往往伴随着布局的变化,代价较大:
重绘只是样式的变化,结构不会变化:
浏览器的帮忙:
所以我们能得知回流比重绘的代价要更高,回流的花销跟render tree有多少节点需要重新构建有关系
因为这些机制的存在,所以浏览器会帮助我们优化这些操作,浏览器会维护1个队列,把所有会引起回流、重绘的操作放入这个队列,等队列中的操作到了一定的数量或者到了一定的时间间隔,浏览器就会flush队列,进行一个批处理。这样就会让多次的回流、重绘变成一次回流重绘。
4.应该尽量减少回流和重绘,那么怎样优化浏览器渲染过程?
其实优化就是减少对render tree的操作,并减少对一些style信息的请求,尽量利用好浏览器的优化策略。
1.不要1个1个改变元素的样式属性,最好直接改变className,但className是预先定义好的样式,不是动态的,如果你要动态改变一些样式,则使用cssText来改变
2.DOM的增删行为
让操作元素离线处理,即使用documentFragment或div等元素进行缓存操作,先把所有要添加到元素添加到1个div,最后才把这个div append到body中
3.先display:none 隐藏元素,然后对该元素进行所有的操作,最后再显示该元素。因对display:none的元素进行操作不会引起回流、重绘。
4.将引起回流的属性赋值给变量,进行缓存,需要用到的时候直接使用变量就行。例如获取一个元素的scrollTop、scrollLeft、scrollWidth、offsetTop、offsetLeft、offsetWidth、offsetHeight之类的属性,浏览器为了保证值的正确也会回流取得最新的值,所以如果你要多次操作,最取完做个缓存。
5.减少操作影响的节点,影响的节点越多,则越消耗性能。