了解浏览器的渲染原理才能很好地优化代码,使浏览器更快地加载页面,最近看了篇文章,学到了很多,所以整理一下思路,写下了这篇文章,原文在这里
本文只讨论当浏览器拿到页面之后是如何进行渲染的,不讨论网络通信部分。
各个浏览器由于使用的内核不同,渲染引擎也就不同,但主要流程大致相同。
不同的浏览器使用不同的渲染引擎:
IE使用Trident
Firefox使用Gecko
Safari使用WebKit
Chrome和Opera(版本15开始)使用Blink。它是基于Webkit开发的。
浏览器的构成
webkit渲染流程
所以浏览器的渲染过程大致分为以下几个过程:
- 解析HTML生成DOM树。
- 解析CSS生成CSSOM规则树。
- 将DOM树和CSSOM规则树合并在一起生成渲染树。
- 遍历渲染树开始布局,计算每个节点的位置大小信息,精确定位
- 将渲染树每个节点绘制到屏幕上。
那么浏览器到底是怎么解析,怎么渲染的呢?到底是先解析生成了DOM树,然后再加载生成CSS JS文件进行渲染,还是在解析DOM树的过程中同时也解析CSS 呢?
当浏览器加载完HTML之后,开始解析HTML,解析过程中如果遇到了link标签,会再次向服务器发起请求,加载CSS文件,加载CSS文件的过程是异步的,也就是说加载CSS文件的时候,浏览器仍然在解析HTML文件,加载完CSS文件后开始解析CSS样式表,解析CSS样式表和解析HTML的过程仍然是一起进行的,因为解析CSS样式表的过程并不会改变DOM树,所以,两者可以一起进行,如果解析HTML的过程遇到了script标签,则JS文件会阻塞HTML的解析过程,会停止HTML的解析,直接加载script文件,script文件加载完成后立马执行(这是因为js可能会修改DOM结构,浏览器为了防止出现JS修改DOM结构,需要重新构建DOM树的情况出现,所以就会阻塞其他内容的下载和呈现)。等js文件执行完毕后,才会继续解析HTML文档。
构建DOM树
当浏览器接收到服务器的HTML文档后,会遍历文档节点,生成DOM树。
需要注意的是,DOM树的构建过程遵循深度优先原则,即当前元素的所有子节点都构建好之后才会去构建当前节点的下一个兄弟节点。
构建CSSOM规则树
浏览器解析CSS文件并生成CSS规则树。CSS解析时遵循的原则是从右向左,即如果现在有一个选择器#div li,浏览器会先找到所有的li标签,然后再挨个匹配父元素。
构建渲染树
通过DOM树和CSS规则树我们便可以构建渲染树。浏览器会先从DOM树的根节点开始遍历每个可见节点。对每个可见节点,找到其适配的CSS样式规则并应用。
渲染树构建完成之后,每个节点都是可见节点,并且都包含其内容和对应的样式规则,这也是渲染树与DOM树的最大区别所在,渲染树是用于显示,那些不可见的元素当然不会出现在渲染树中,除此之外,display为none的元素也不会被挂到这棵树上。
根据渲染树开始布局
布局阶段会从渲染树的根节点开始遍历,然后确定每个节点对象在页面上的确切大小和具体位置,布局阶段的输出是一个盒子模型,它会精确的捕获每个元素在屏幕内的确切位置与大小。
渲染树绘制
在绘制阶段,遍历渲染树,调用渲染器的paint()方法,在屏幕上显示其内容,渲染树的绘制工作是由浏览器的UI后端进行的。
有了上面浏览器渲染页面的整个过程,我们就可以优化代码了。
首先要介绍几个概念:
重构:(reflow) 当浏览器发现某个元素发生了变化,并且这个变化可能会影响其他节点的布局的时候,浏览器就会倒回去重新渲染页面。
重绘:(repaint) 如果只是改变了某个元素的背景颜色,文字颜色等,不影响元素周围或内部布局,则会引起浏览器的重绘,就是重新画某一部分。
重构是针对于整个页面进行的,而重绘只是针对于某一部分,因此重构比重绘花的时间要长。所以在写代码的时候,要尽量避免浏览器的重构。
一般情况下,会造成浏览器重构的有以下几种情况:
(1) 元素的尺寸变化
(2) dom元素的添加,删除,修改等
(3) display: none的情况
重绘的情况:
(1) 元素的背景颜色变化
(2) 字体颜色变化
代码优化
css部分:
- 编写css代码时应该注意dom深度尽量浅
- 不要为id选择器指定类名或是标签,因为id可以唯一确定一个元素。
- 避免使用后代选择符,尽量使用子代选择符,因为子代选择符匹配概率要大于后代选择符。
- 避免使用通配符
- css文件的位置一般放在head里,因为css树和dom树会共同构建渲染树,所以应尽可能早的解析css文件。
js部分:
6. 将所有script标签放在页面底部,也就是body闭合标签之前,这能确保在脚本执行之前已经完成了DOM树的渲染。
7. 尽可能的合并脚本,页面中的script标签越少,加载也就越快,响应也就越迅速,无论是外链脚本还是内嵌脚本都是如此。
8. 采用异步下载方法