浏览器是如何解析一个html页面的?
第一步,构建DOM树
浏览器的渲染引擎,首先解析HTML文档,将html的标签转换为DOM树。
第二步,构建渲染树
浏览器引擎,继续渲染CSS样式文件,这里就包括JS,CSS,html指令,构建相应的渲染树。
第三步,渲染页面
渲染引擎结合DOM树和渲染树,共同渲染,进行具体元素的绘制工作。
当render tree中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建, 这就称为回流(reflow)。
每个页面至少需要一次回流,就是在页面第一次加载的时候。在回流的时候,浏览器会使渲染树中受到影响的部分失效,并重新构造这部分渲染树,完成回流后,浏览器会重新绘制受影响的部分到屏幕中,该过程成为重绘。
重绘(repaint或redraw):
当盒子的位置、大小以及其他属性,例如颜色、字体大小等都确定下来之后,浏览器便把这些原色都按照各自的特性绘制一遍,将内容呈现在页面上。重绘是指一个元素外观的改变所触发的浏览器行为,浏览器会根据元素的新属性重新绘制,使元素呈现新的外观。触发重绘的条件: 改变元素外观属性。如: color, background-color等。注意:table及其内部元素可能需要多次计算才能确定好其在渲染树中节点的属性值,比同等元素要多花两倍时间,这就是我们尽量避免使用table布局页面的原因之一。
回流(重构/重排/reflow):
当渲染树中的一部分(或全部)因为元素的**规模尺寸,布局,隐藏等改变而需要重新构建,这就称为回流。**每个页面至少需要一次回流,就是在页面加载的时候。重绘和回流的关系:在回流的时候,浏览器会使渲染树中受到影响的部分失效,并重新构造这部分渲染树,完成回流后,浏览器会重新绘制受影响的部分到屏幕中,该过程称为重绘。So, 回流必定会引发重绘,但重绘不一定引发回流。
触发回流的条件: 任何页面布局和几何属性的改变都会触发回流比如:1.页面渲染初始化:(无法避免)2.添加或删除可见的DOM元素;3.元素位置的改变,或者使用动画;4.元素尺寸的改变–大小,外边距,边框;5.浏览器窗口尺寸的变化(resize事件发生时);6.填充内容的改变,比如文本的改变或图片大小改变而引起的计算值宽度和高度的改变;7.读取某些元素属性:(offsetLeft/Top/Height/Width, clientTop/Left/Width/Height,scrollTop/Left/Width/Height, width/height, getComputedStyle(), currentStyle(IE))
三、优化(减少回流、重绘)浏览器本身的优化策略:浏览器会维护1个队列,把所有会引起回流、重绘的操作放入这个队列,等队列中的操作到了一定的数量或者到了一定的时间间隔,浏览器就会flush队列,进行一个批处理。这样就会让多次的回流、重绘变成一次回流重绘。但有时候我们写的一些代码可能会强制浏览器提前flush队列,这样浏览器的优化可能就起不到作用了。当你请求向浏览器请求一些 style信息的时候,就会让浏览器flush队列。
减少对render tree的操作(合并多次多DOM和样式的修改),并减少对一些style信息的请求,尽量利用好浏览器的优化策略方法:
1. 将多次改变样式属性的操作合并成一次操作。
2.将需要多次重排的元素,position属性设为absolute或fixed,这样此元素就脱离了文档流,它的变化不会影响到其他元素。例如有动画效果的元素就最好设置为绝对定位。
3. 在内存中多次操作节点,完成后再添加到文档中去。例如要异步获取表格数据,渲染到页面。可以先取得数据后在内存中构建整个表格的html片段,再一次性添加到文档中去,而不是循环添加每一行。
4. 由于display属性为none的元素不在渲染树中,对隐藏的元素操作不会引发其他元素的重排。如果要对一个元素进行复杂的操作时,可以先隐藏它,操作完成后再显示。这样只在隐藏和显示时触发2次重排。
5. 在需要经常取那些引起浏览器重排的属性值时,要缓存到变量。