那些我所忽略的内容,浅谈浏览器对HTML的渲染

1.写在前面

什么是渲染?

渲染即把文件解析并以具体内容显示在页面的过程,我们依托各种浏览器实现了这一个所见即所得的过程,相信很多人选择前端的原因便是前端能够给你一个快速且具体的反馈,那么浏览器是如何实现这一个过程的呢,这篇文章将围绕以下方面展开。

  • 浏览器渲染机制
  • reflow 🆚 repaint - HTML的回流与重绘
  • 渲染的阻塞问题

2.浏览器渲染机制

2.1关键渲染路径 Critical Rendering Path

关键渲染路径即浏览器请求到HTML,CSS,JS开始,到最后将页面渲染到浏览器上的过程,其大致可以分为构造DOM(文档对象模型),构建CSSOM(CSS对象模型),构建RenderTree(渲染树),布局计算像素绘制

2.1.1 DOM

在浏览器渲染的过程中涉及到两个最关键的概念,DOM解析DOM渲染 ,DOM是我们耳熟能详的一个概念,我们先来简单回顾一下何为DOM,DOM树是什么。

先来抛一些定义,DOM(文档对象模型)是一种用于表示和操作HTML、XML和XHTML文档的编程接口。在Web开发中,DOM充当了网页内容的结构化表示,它将网页中的每个元素(如标签、文本和属性)都表示为对象,并提供了一组方法和属性来操纵这些对象。

这些概念文绉绉的,可能很多人像我一样,看到的第一眼压根就不清楚这到底是个什么东西,是用来干嘛的,首先我们明确一个概念DOM树主要由4类主要节点组成:文档节点,元素节点,属性节点,文本节点。DOM Tree便是将你所写的各种html标签按照层级结构生成的有序节点组合我们可以把整个文件看作是一颗树,其有非常多的层级结构, 我们可以把这些理解为一颗树的分支,我们可以获取这个分支去对这个HTML过程进行操作。

2.2 构建DOM

上文提到了DOM Tree的定义,那么浏览器在背后是怎么悄悄咪咪地给我们构建出这么一颗树的呢?其过程其实就是以下阶段。

  • 标签转化
    由于html文件字节流无法直接被渲染引擎理解,当浏览器获取到html文件之后会按照指定的编码规范将每个字节转化为可识别的单个字符
  • 字符串解析
    在这个阶段中,浏览器会将每个字符(比如说body,html)解析成一个个独有的Token,并将这些Token转化成object对象,对象中包含着这些标签的属性
  • 组合DOM Tree
    将这些唯一的object按照层级结构组合起来,这便形成了我们所熟悉的DOM Tree

2.3构建CSSOM CSS Object Model

CSSOM的构建过程与前面提到的DOM Tree构建过程是类似的,我们想要使用CSS进行样式调整的时候就需要去引入CSS,当浏览器识别到这个过程之后便会请求CSS文件并进行相应的解析。并且构建出来的模型也会是树形结构 ,这是为什么?

用一个我们熟知的概念去阐述,那便是CSS具有继承的特性,当我们使用CSS调整样式的时候,我们总希望能够通过层级的结构方便获取对应节点例如:

css 复制代码
body {
  font-size: 16px; 
} 
p {
  font-family: serif; 
} 
p span {
  color: white; 
}
span {
  color: red; 
}

对于浏览器来说也是如此,构建出树形结构更有利于浏览器从最顶层的节点开始,一层层向下解析,最终返回我们想要的最终样式。

2.4 构建Render Tree

构建Render Tree便是将上文所提及的DOM TreeCSSOM相结合

在构建的过程中,浏览器大致会进行以下过程

  • DOM树根节点开始遍历节点
  • 当所遍历节点在CSSOM上有相对应的节点时进行匹配
  • 在Render Tree中进行挂载,生成Render Tree

2.5 布局计算与像素绘制

当构建好了渲染树之后我们得到了该文件的所有元素信息,在这个阶段我们还不能够直接将我们的元素绘制到设备上,这是因为浏览器还并不知道每一个节点在设备上的对应位置以及大小,这便是布局计算Layout所需要进行的内容。

布局计算我们将会采用盒子模型计算每个节点与元素的距离从而获取每个元素位于设备中的大小与位置。

Layout过程结束后,浏览器已经明确了每个节点的样式以及大小形状,我们就可以将这些节点信息转化为设备上实际的像素点,渲染出html最终的结果。

3. reflow与repaint

回流与重绘是两个相关但又不完全相同的概念

  • 回流:重新渲染布局,重新排列元素
  • 重绘:元素外观被改变,重新渲染

根据以上概念我们可以得知,当布局元素高度,宽度变化重新被渲染的时候,必定会导致周边的元素进行重绘,但是单单改变元素的颜色并不会让整个页面进行重新布局渲染,由此我们可以知道:

回流必定会导致重绘,重绘不一定会导致回流。

3.1 reflow(回流)

浏览器的回流reflow是指在渲染网页时,浏览器计算并确定元素的布局和几何属性的过程。当网页的结构或样式发生变化时,浏览器需要重新计算并更新元素的位置、大小和其他相关属性,以便正确地显示页面。 回流可能会对网页的性能产生负面影响,特别是在具有复杂布局和大量元素的页面上。频繁的回流操作可能导致页面的重新渲染延迟,降低用户体验。因此,在编写和优化网页时,需要尽量减少回流的次数和范围。

以下是一些常见触发回流的操作:

  • 修改元素的尺寸(宽度、高度)
  • 修改元素的位置(定位属性、外边距、内边距)
  • 修改元素的内容或文本
  • 修改元素的字体大小
  • 添加或删除可见的 DOM 元素
  • 修改浏览器窗口大小

3.2 repaint(重绘)

浏览器的重绘repaint是指在渲染网页时,当元素的外观发生变化而不影响其布局时,浏览器重新绘制元素的过程。重绘只涉及更新元素的视觉呈现,而不会重新计算和调整元素的位置、大小或其他布局属性。当元素的外观属性发生变化时,例如背景颜色、字体颜色、边框样式等,浏览器会触发重绘操作。重绘过程会重新绘制元素的视觉内容,以确保元素显示正确的外观。

4.渲染阻塞

浏览器渲染阻塞是指在网页加载过程中,浏览器在进行页面渲染时受到某些因素的影响,导致页面渲染的进程被延迟或阻塞。这可能会导致用户在浏览网页时出现延迟或卡顿的感觉。

4.1 CSS 🆚 渲染解析与阻塞

  • 导致DOM渲染阻塞
    到这里我们已经知道了DOM TreeCSSOM的解析是并行的,两者进行解析的时候互不影响,因此CSS并不会阻塞DOM的解析,但是由于在构建Render Tree的时候需要同时解析两者,当DOM Tree完成但CSSOM Tree并未完成的时候会影响Render Tree的生成,导致DOM的渲染阻塞
  • 阻塞JS解析
    先介绍一下浏览器的GUI渲染线程,负责渲染浏览器界面,解析 HTML,CSS,构建 DOM 树和 Render树,布局和绘制等。但就是这个负责渲染的家伙与JS引擎的线程是互斥的!而浏览器为了防止渲染线程前后的元素数据不一致,当遇到scrip标签的时候会组织解析器继续操作,直到CSSOM构建完毕,JS才会运行并继续完成Dom Tree也就是说 !在构建CSSOM的时候会阻塞JS的执行

4.2 JS 🆚 渲染解析与阻塞

  • JS阻塞渲染
    浏览器在解析HTML文档时遇到JavaScript代码时,会立即执行该代码。执行JavaScript代码可能会修改DOM结构、样式或触发其他JavaScript代码,这就需要浏览器停止当前的解析和渲染进程,转而执行JavaScript代码。执行过程中,可能会修改DOM结构、样式、绑定事件等操作,这就需要浏览器停止当前的渲染进程,重新计算布局和渲染页面。因此,JavaScript的执行阶段也会阻塞页面的渲染。
  • 导致线程阻塞
    我们都知道JS的执行是单线程的,即一次只能执行一个任务,因此如果JavaScript代码的执行时间较长,会导致页面在此期间停止响应,出现页面卡顿或加载延迟的情况。

4.2.1 如何解决js阻塞问题?

一个很好的方法就是使用异步脚本async,将JS的响应时间延长,但使用异步脚本只是在网络请求期间让Dom的构建继续进行,但是在执行的时候依然会阻塞Dom

写在最后

这篇文章是我对浏览器渲染原理学习的总结与理解,能力有限并不能将其全部内容详细的进行分析,疏漏之处,欢迎指正。

vitasTsui   2023.10.21

相关推荐
万叶学编程2 小时前
Day02-JavaScript-Vue
前端·javascript·vue.js
前端李易安4 小时前
Web常见的攻击方式及防御方法
前端
PythonFun4 小时前
Python技巧:如何避免数据输入类型错误
前端·python
知否技术4 小时前
为什么nodejs成为后端开发者的新宠?
前端·后端·node.js
hakesashou4 小时前
python交互式命令时如何清除
java·前端·python
天涯学馆4 小时前
Next.js与NextAuth:身份验证实践
前端·javascript·next.js
HEX9CF5 小时前
【CTF Web】Pikachu xss之href输出 Writeup(GET请求+反射型XSS+javascript:伪协议绕过)
开发语言·前端·javascript·安全·网络安全·ecmascript·xss
ConardLi5 小时前
Chrome:新的滚动捕捉事件助你实现更丝滑的动画效果!
前端·javascript·浏览器
ConardLi5 小时前
安全赋值运算符,新的 JavaScript 提案让你告别 trycatch !
前端·javascript