关于浏览器渲染原理流程

1、一个经典的问题:向浏览器输入URL地址,发生了什么

而这部分也只是在说浏览器获取数据的部分(也就是页面加载的过程),至于浏览器拿到数据后是如何渲染的呢(不同浏览器渲染引擎不相同,这里以Webkit为例)

2、浏览器渲染过程

流程图如下:

  1. 解析HTML,生成DOM树;解析CSS,生成CSSOM树

  2. 将DOM树和CSSOM树结合,生成渲染树Render Tree

  3. Layout回流:根据生成的渲染树,进行回流,得到节点的几何信息(位置、大小)

  4. Painting重绘:根据渲染树以及回流得到的几何信息,得到节点的绝对像素

  5. Display:将像素发送给GPU,最后通过调用操作系统Native GUI的API绘制,展示在页面上

2.1 构建DOM树的过程

  • 【字节数据】:网络中传输的内容其实是0和1这种字节数据,浏览器从磁盘或网络读取HTML的字节数据
  • 【字符串】: 浏览器并根据文件的指定编码(如UTF-8)将它们转换为字符串
  • 【Token】: 浏览器将字符串转换为W3CHTML5标准规定的各种令牌Token,例如、等其他尖括号内的字符串,Token中会标识出当前Token是'开始标签'还是结束标签'还是'文本'等信息,每个令牌都具有特殊含义和一组规则。
  • 【Node】:紧接着这些标记会被转换为Node。事实上,不是等所有Token都转换完再去生成节点对象,而是一边生成Token一边消耗Token来生成节点对象。(带有结束标签标识的Token不会创建节点对象)
  • 【DOM】:这些Node会根据不同Node之间的联系生成DOM树🌲

举例:HTML文本:

这段HTML就会解析成:

2.2 构建CSSOM的过程

这个过程与构建DOM的过程很相似,当浏览器接收到一段CSS,浏览器首先要做的就是识别出Token,然后构建节点并生成CSSOM。

浏览器会根据CSS规范来解析CSS,与DOM不同的是CSS会向下层叠,即子节点可能会继承父节点的一些属性。浏览器解析CSS过程是阻塞的,需要解析完所有的CSS才会使用CSS样式

CSS解析可以与DOM解析同时进行,如果只有CSS和HTML的页面,CSS不会影响DOM树的创建,但是页面中还有JS的话,就不一样了

  • 第一种情况:当前页面中只有HTML和JS,且JS非外部引入

先去执行JS的原因是:JS可能会操作到当前已经生成的DOM节点

  • 第二种情况:当前页面中同时有HTML、CSS、JS,且都非外部引入

因为JS可能会操作CSSOM节点

  • 第三种情况:当前页面中只有HTML和JS,且JS非外部引入

Webkit渲染引擎有一个优化,当渲染进程接收HTML文件字节流时,会先开启一个预解析线程,如果遇到JS文件或者CSS文件,那么预解析线程会提前下载这些数据

2.3 构建渲染树

通过DOM树和CSSOM树,浏览器就可以通过二者构建渲染树了。浏览器会先从DOM树的根节点开始遍历每个可见节点,然后对每个可见节点找到适配的CSS样式规则并应用。

  • DOM树与Render树不是一一对应的

  • visibility:hidden和display:none是不一样的,前者隐藏元素,但元素仍占据着布局空间(即渲染成一个空框),而后者将元素从渲染树中完全移除,元素既不可见,也不是布局的组成部分

样式计算是个很复杂的问题,DOM中的一个元素对应样式表中的多个元素。样式表包括了所有样式:浏览器默认样式表、自定义样式表、inline样式表。

2.4 布局Layout

创建渲染树后,下一步就是布局(或者是回流),布局流程的输出是一个盒模型,会精确地捕获每个元素在视口内的确切位置和尺寸,所有相对测量值都将转换为屏幕上的绝对像素。将每个元素安置在浏览器窗口的正确位置。

而有时候我们在文档布局完成后对DOM进行修改,这时候可能会引发重新布局。

对渲染树的布局可分为全局和局部的,全局即对整个渲染树进行重新布局,比如当改变了窗口尺寸或方向或修改了根元素的尺寸或字体大小;而局部可以是对某部分或某一个渲染对象进行重新布局

布局是一个从上到下,从外到内进行的递归过程,从根渲染对象,即对应着HTML文档根元素,然后下一级渲染对象,即对应着元素,如此层层递归,依次计算每一个渲染对象的几何信息

每一个渲染对象的布局流程:

2.5 绘制Painting

在绘制阶段,系统会遍历渲染呈现树,并调用呈现器的Paint方法,将呈现器的内容显示在屏幕上。(我们通过构造渲染树和回流阶段,我们知道了哪些节点是可见的,以及可见节点的样式和具体的几何信息(位置、大小),那么我们就可以将渲染树的每个节点都转换为屏幕上的实际像素)

3、回流重绘

回流这一阶段主要是计算节点的位置和几何信息,那么当页面布局和几何信息发生变化的时候,就需要回流

何时会触发回流呢:

  • 页面一开始渲染的时候
  • 浏览器的窗口尺寸变化(因为回流是根据视口的大小来计算元素的位置和大小的)
  • 添加或删除可见的DOM元素
  • 元素的位置发生变化
  • 元素的尺寸发生变化(包括外边距、内边距、边框大小、高度和宽度等)
  • 内容发生变化,比如文本变化或图片被另一个不同尺寸的图片替代
  • 元素字体大小变化
  • 激活CSS伪类(如:hover)
  • display:none触发回流,visibility:hidden只会触发重绘

页面中元素样式改变但不影响在文档的位置时,不触发回流,只触发重绘。(回流一定会触发重绘,而重绘不一定会回流)

回流的成本要比重绘要更高,如何进行优化,减少回流和重绘呢:

  • 样式结构层级尽量简单,CSS选择符从右往左匹配查找
  • 在脚本中尽量减少DOM操作,尽量缓存访问DOM的样式信息
  • 减少通过JS代码修改元素样式,尽量使用修改class名方式操作样式或动画
  • 使用transform代替top
  • 使用visibility代替display:none
  • script标签的使用加defer或async属性(defer:表示js文件会并行下载,但是会放到HTML解析完成后顺序执行;async:表示JS文件下载和解析不会阻塞渲染)
  • 不要使用table布局(小改动可能造成整个table重新布局)

最后

来自一位小白的梳理 如果有什么问题欢迎评论区沟通~

相关推荐
Cacciatore->1 分钟前
React 基本介绍与项目创建
前端·react.js·arcgis
摸鱼仙人~2 分钟前
React Ref 指南:原理、实现与实践
前端·javascript·react.js
teeeeeeemo4 分钟前
回调函数 vs Promise vs async/await区别
开发语言·前端·javascript·笔记
贵沫末22 分钟前
React——基础
前端·react.js·前端框架
aklry34 分钟前
uniapp三步完成一维码的生成
前端·vue.js
Rubin9341 分钟前
判断元素在可视区域?用于滚动加载,数据埋点等
前端
爱学习的茄子42 分钟前
AI驱动的单词学习应用:从图片识别到语音合成的完整实现
前端·深度学习·react.js
用户38022585982442 分钟前
使用three.js实现3D地球
前端·three.js
程序无bug44 分钟前
Spring 面向切面编程AOP 详细讲解
java·前端
zhanshuo44 分钟前
鸿蒙UI开发全解:JS与Java双引擎实战指南
前端·javascript·harmonyos