浏览器的渲染原理
渲染的整个流程
基本概念
DOM Tree
:浏览器将HTML解析成树形的数据结构的DOM树(Document Object Model
)
CSS Tree
:浏览器将CSS解析成树形的数据结构的CSS树(CSS Object Model
)
render tree
:DOM树和CSS树合并后生成渲染树
layout tree
:渲染树经过样式计算,确定各个节点在页面中的具体位置生成布局树
painting
:调用GPU进程将布局树进行绘制渲染在页面
浏览器获得HTML文件后,会先进行预编译,请求js、css或图片,然后自上而下的解析,
如果遇到Javascript文件,HTML文件会挂起渲染的进程,等待JavaScript文件加载完毕后,再继续进行解析;如果遇到css文件
HTML会继续进行解析,解析css的同时也在解析dom,css文件虽然不会阻塞HTML的解析,但会阻塞页面的渲染。
问:
为什么HTML需要等待JavaScript
呢?
因为JavaScript可能会修改DOM,导致后续HTML资源白白加载,所以HTML必须等待JavaScript
文件加载完毕后,
再继续解析,这也就是为什么JavaScript
文件在写在底部body标签前的原因
由于<script>
标签是阻塞解析的,将脚本放在网页尾部会加快代码渲染
为什么css会阻塞页面的渲染呢?
因为生成的渲染树,需要等待css文件解析完成后生成的css树与DOM树合成渲染树
由于css是和HTML同步解析的,但会阻塞渲染,所以css文件放在网页头部会加快渲染
浏览器渲染的五个阶段
第一步 解析HTML
构建DOM
树
HTML解析器会解析HTML文件,解析出来的结果会成为一棵dom树(包含全节点,包括隐藏的节点和<head>
标签)
第二部 解析css
构建css
树
空
第三部 生成渲染树
将生成的的dom树和css树相结合,成为一颗新的渲染树 render tree
;
render tree
不会将所有原本的dom树全部构建出来,一些不需要显示的元素则不会被构建到render tree
中
- 渲染树不会添加 css中设置为
display:none
的dom
元素 - 渲染树不会添加
<head>
标签中的元素
第四部 生成布局树
对生成的渲染树进行样式计算,确定各个元素在页面中的具体位置,生成布局树
第五步 绘制(painting
)
生成布局树后,浏览器主进程调用GPU
进程对布局树进程绘制,渲染在页面上
性能分析
重绘是当节点需要更改外观而不会影响布局的,比如改变color
就叫称为重绘
回流是布局或者几何属性需要改变就称为回流。 回流必定会发生重绘,重绘不一定会引发回流。回流所需的成本比重绘高的多,改变深层次的节点很可能导致父节点的一系列回流
当js脚本中存在修改会影响dom的布局时,会产生回流(Reflow
),回流会让浏览器重新执行第四步和第五步的操作
当js脚本中存在修改会影响dom样式,但不影响布局时,会产生重绘(Repaint
),重绘会让浏览器重新执行第五步的操作
使用不同的图层来渲染页面
页面是一个二维平面,但层叠上下文能够让HTML元素拥有三维概念,这些HTML元素按自身属性的优先级分布在垂直于这个二维平面的Z轴上,以下情况会作为单独的图层,
不同的图层渲染互不影响,所以对于某些频繁需要渲染的建议单独生成一个新图层,提高性能。
1、position:fixed
2、css 3d 例如:transform:rotateX(30deg)
3、video
4、canvas
5、有css3动画的节点
display: none; 和 visibility: hidden;的区别
- 占用位置的区别:
display: none; 不会占用位置
visibility: hidden; 虽然隐藏了,会占用位置 - 重绘和回流的问题
visibility: hidden; display: none; 会产生一次重绘
display: none; 还回产生一次回流
产生回流一定会产生重绘
但产生重绘不一定会产生回流