目录
1. 浏览器渲染基本步骤2. 构建DOM树、CSSOM树3. 构建渲染树4. 计算渲染树的布局5. 将布局渲染到屏幕上6. 渲染优化1. 浏览器渲染基本步骤
浏览器主要有以下步骤:
浏览器通过HTTP协议向服务端请求页面数据将请求回来的HTML文件解析成DOM树将请求回来的CSS文件解析成CSSOM树将DOM树和CSSOM树结合在一起,生成渲染树(render tree)计算渲染树的布局,这实际上是回流的过程将布局渲染到屏幕上,这实际上是重绘的过程
大致过程如图所示:
这里主要说说后面解析的过程。
2. 构建DOM树、CSSOM树
构建DOM树:
首先来看HTML文件的解析,在解析过程中,如果遇到<script>
就会停止页面的解析,先执行标签中的JavaScript代码,如果代码时外联的形式,也需要等待外联的JavaScript代码下载并执行完才继续执行解析HTML的工作,解析完HTML文件之后,就会触发DOMContentLoaded
事件,这时就可以操作DOM了。
构建CSSOM树:
下面来看CSS的解析,我们从上面的图中可以看到HTML解析和CSS解析是同步进行的,也就是并行处理的,这样就不会在渲染的内容没有样式。在解析过程中,如果遇到script标签,和上面的处理方式一样。CSS解析器最终会将CSS解析为CSSStyleSheet(也就是CSSOM树),具体的结果如下:
CSS是一种渲染阻塞资源(render blocking resource),它需要完全被解析完毕之后才能进入生成渲染树的环节。
由于CSS有些属性具有继承性,后面定义的样式可能会覆盖或修改前面的样式,所以只有当所有的CSS代码都执行渲染完之后才能进入下一个环节。在CSSOM构建完成之前,页面都会处于白屏状态,所以,一般都是在文件的头部引入CSS文件。
3. 构建渲染树
当DOM树和CSSOM树都解析完之后,就会一起合成渲染树( Render Tree ),如下图所示:
在合并生成渲染树的过程中,有以下几点需要注意:
元素如果被设置为display:non
e,在 DOM 树中依然会显示,但是在 Render 树中不会显示;元素如果被设置为visibility:none
,那么 DOM 树和 Render 树中都会显示;我们经常说的脱离文档流,其实就是脱离 Render Tree。
4. 计算渲染树的布局
这一步实际上就是回流的过程。在这一阶段,会从渲染树的根节点开始遍历,由于渲染树的每个节点都是一个Render Object 对象,这个对象包含元素的的宽高、位置、颜色、内容等信息。所以浏览器会根据这些信息来确定每个节点对象在页面上的位置和大小,这一阶段输出的就是盒子模型,它会精确捕获每个元素在屏幕内的确切位置和大小,不过需要注意的是:设置了float,absoulte,fixed的元素会发生位置偏移。
5. 将布局渲染到屏幕上
在绘制阶段,浏览器会遍历渲染树,调用渲染器的paint()
方法在屏幕上显示其内容。
上述五个步骤都是浏览器渲染进程中的GUI渲染线程完成的。
GUI渲染线程主要的工作如下:
负责渲染浏览器页面,解析HTML、CSS,构建DOM树、CSSOM树、渲染树和绘制页面当界面需要重绘或由于某种操作引发回流时,该线程就会执行
6. 渲染优化
针对JavaScript:
JavaScript既会阻塞HTML的解析,也会阻塞CSS的解析。因此我们可以对JavaScript的加载方式进行改变,来进行优化:
(1)尽量将JavaScript文件放在body的最后
(2) body中间尽量不要写<script>
标签
(3)-<script>
标签的方式有三种,有一种就是我们常用的直接引入,还有两种就是使用 async 属性和 defer 属性来异步引入,两者都是去异步加载外部的JS文件,不会阻塞DOM的解析(尽量使用异步加载)。三者的区别如下:
script立即停止页面渲染去加载资源文件,当资源加载完毕后立即执行js代码,js代码执行完毕后继续渲染页面async是在下载完成之后,立即异步加载,加载好后立即执行,多个带async属性的标签,不能保证加载的顺序defer是在下载完成之后,立即异步加载。加载好后,如果 DOM 树还没构建好,则先等 DOm 树解析好再执行;如果DOM树已经准备好,则立即执行。多个带defer属性的标签,按照顺序执行
针对CSS:
使用css有三种方式:使用link、@import、内联样式,其中link和@import都是导入外部样式。它们之间的区别:
link:浏览器会派发一个新等线程(HTTP线程)去加载资源文件,与此同时GUI渲染线程会继续向下渲染代码@import:GUI渲染线程会暂时停止渲染,去服务器加载资源文件,资源文件没有返回之前不会继续渲染(阻碍浏览器渲染)style:GUI直接渲染
另外外部样式如果长时间没有加载完毕,浏览器为了用户体验,会使用浏览器会默认样式,确保首次渲染的速度。所以CSS一般写在headr中,让浏览器尽快发送请求去获取css样式。
所以,在开发过程中,导入外部样式使用link,而不用@import。如果css少,尽可能采用内嵌样式,直接写在style标签中。
针对DOM树、CSSOM树:
可以通过以下几种方式来减少渲染的时间:
HTML文件的代码层级尽量不要太深使用语义化的标签,来避免不标准语义化的特殊处理减少CSSD代码的层级,因为选择器是从左向右进行解析的
减少回流与重绘:
这里就不多说了,参考《【前端性能优化】回流与重绘》
最后,再补充一个知识点:Load 和 DOMContentLoaded 区别是什么?
Load 事件触发代表页面中的 DOM,CSS,JS,图片已经全部加载完毕。DOMContentLoaded 事件触发代表初始的 HTML 被完全加载和解析,不需要等待 CSS,JS,图片加载