一文彻底搞懂浏览器渲染原理(超详细版)

浏览器渲染原理

渲染时间点

渲染时间点

1. 解析 HTML - Parse HTML

解析 HTML
DOM 树
CSSOM 树

每一个样式表会形成一个 CSStyleSheet 节点

  • <style></style>
  • <link ...>
  • <div style="color: red">
  • 浏览器默认样式表

body、div 等为什么是 block?因为默认样式表中设置了 display: block

head 为什么看不见?因为默认样式表中设置了 display: none

除了默认样式,其他样式 JS 都能操作

行内样式直接使用 dom.style 操作

<style></style><link ...> 可以在控制台中使用 CSSOM 树 document.styleSheets 操作

将网页中所有 div 都加边框:document.styleSheets[0].addRule('div', 'border: 2px solid #f40 !important')

HTML 解析过程中遇到 CSS 代码怎么办?

为了提高解析效率,浏览器会启动一个预解析器率先下载和解析 CSS

预解析线程-CSS

如果渲染主线程解析到 link 位置,此时外部的 CSS 文件还没下载解析好,主线程不会等待

如果解析到 script 位置,会停止解析 HTML,转而等待 JS 文件下载好,并将全局代码解析执行完成后,才能继续解析 HTML,因为 JS 代码中可能会操作 DOM 树
预解析线程-JS

2. 样式计算 - Recalculate Style

样式计算
会计算出最终样式(也叫计算后的样式,Computed Style)
最终样式

自己写的样式可能很少,但最终样式可能会很多

在这一过程中,很多预设值会变成绝对值,比如 red 会变成 rgb(255,0,0)

相对单位会变成绝对单位,比如 em 会变成 px

这一步完成后,会得到一棵带有样式的 DOM 树

这个阶段算不出来相对单位转换后的绝对数值,比如 width: 70% 在这个阶段算不出来

JS 如何获取最终样式?getComputedStyle()

3. 布局 - Layout

布局

根据 DOM 树(带样式)算出每个元素的位置、尺寸等,形成 Layout 树(包含每个节点的几何信息)

位置是相对包含块的位置(不是父级的位置)

比如说三个嵌套的盒子,最外面的盒子定位了,那么最里面的盒子的位置是相对已定位的盒子(最外面的盒子)的,而不是相对它的父级

同理,width: 70% 也是相对包含块的宽度

DOM 树和 Layout 树并不是一一对应的

Layout 树-1

Layout 树-2

Layout 树-3

JS 中不能直接获取 Layout 树的对象,但是能间接获取一些信息:

document.body.clientWidth

4. 分层 - Layer

分层

与堆叠上下文有关的属性(如 z-index)可能会影响分层决策

可以把一些经常变化的元素分为一层,将来变动时只会变动这层的内容

可以使用 will-change 告诉浏览器「这个元素稍后可能会发生某些变化,请提前做好准备!」

will-change 是图层管理的开发接口,允许开发者精细化控制渲染性能,直接影响浏览器渲染管线的优化策略

.box {
  will-change: transform;
  transition: transform 0.3s;
}

.box:hover {
  transform: scale(1.2);
}
  1. will-change

    元素在首次 transform 变化时,浏览器才创建图层 → 可能导致首帧卡顿

  2. will-change

    浏览器在样式计算阶段就分配独立图层 → 动画开始时直接走 GPU 合成

5. 绘制 - Paint

这里的绘制是指生成绘制的指令

绘制

类似于 Canvas

渲染主线程的工作到此为止,剩余步骤交给其他线程完成

渲染主线程完毕

6. 分块 - Tiling

分块会将每一层分为多个小的区域

分块

会先画靠近视口的块

合成线程-分块

合成线程会从线程池中拿取多个线程来完成分块工作

7. 光栅化 - Raster

光栅化是将每个块变成位图(也就是变为每个像素点的信息)

优先处理靠近视口的块

光栅化

光栅化是在 GPU 中做的,所以要用到 GPU 进程

8. 画 - Draw

画

合成线程计算出每个位图在屏幕上的位置,生成 quad(指引信息),交给 GPU 进行最终呈现

为什么要用 GPU 进程中转一下?明明可以直接通知 GPU 的

因为渲染主线程和合成线程处于渲染进程中,渲染进程是在沙盒中的,隔离了硬件,因此必须通过 GPU 进程中转才能通知到 GPU

指引会标识出每个位图应该画到屏幕的哪个位置,以及会考虑到旋转、缩放等变形

为什么说 transform 效率高?因为 transformopacity 等发生在合成线程,与渲染主线程无关

transform 不会改变元素的布局信息,也就是说,不会触发回流(Reflow),它只是在渲染的最终阶段对元素的视觉输出进行变形

transform: translateX(50px),视觉上,浏览器在合成阶段将该元素整体平移 50px,但布局系统不知道这个变化

只有 transformopacity 能完全避免回流(Reflow)

完整过程

完整过程

Python面向对象编程(Object-Oriented Programming,简称OOP)是一种编程范式,它将数据和操作封装在对象中,通过对象之间的交互实现程序的设计和开发。下面是一些关键概念,帮助你更好地理解Python面向对象编程。 1. 类(Class):类是对象的蓝图或模板,描述了对象的属性和行为。它定义了对象的特征和方法。例如,我们可以定义一个名为"Car"的类来表示汽车,其中包含属性(如颜色、型号)和方法(如加速、刹车)。 2. 对象(Object):对象是类的实例,是具体的实体。通过实例化类,我们可以创建一个对象。例如,我们可以创建一个名为"my_car"的对象,它是基于"Car"类的实例。 3. 属性(Attribute):属性是对象的特征,用于描述对象的状态。每个对象都可以具有一组属性。例如,"Car"类的属性可以包括颜色、型号等。 4. 方法(Method):方法是对象的行为,用于定义对象的操作。每个对象都可以具有一组方法。例如,"Car"类的方法可以包括加速、刹车等。 5. 继承(Inheritance):继承是一种机制,允许我们创建一个新类(称为子类),从现有类(称为父类)继承属性和方法。子类可以扩展或修改父类的功能。继承可以实现代码重用和层次化设计。 6. 多态(Polymorphism):多态是一种特性,允许不同类的对象对同一方法做出不同的响应。多态提高了代码的灵活性和可扩展性。 7. 封装(Encapsulation):封装是一种将数据和操作封装在对象中的机制,隐藏了对象的内部实现细节,只暴露必要的接口给外部使用。这样可以保护数据的安全性,提供了更好的模块化和代码复用性。 通过理解这些概念,你可以更好地掌握Python面向对象编程。在实践中,你可以使用类来创建对象,操作对象的属性和调用对象的方法,通过继承和多态实现代码的灵活性和可扩展性,通过封装保护数据的安全性和提高代码的可维护性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值