🛸🛸HTML文档是怎么渲染成我们看到的页面的?

33 阅读6分钟

前言

当你在浏览器地址栏输入一个网址并按下回车时,一场复杂的转换就悄然开始了。服务器返回的HTML文档只是一系列文本标记,而浏览器则承担了将这些抽象符号转化为可视化页面的重任。这个转换过程被称为"渲染",它涉及解析、构建、布局和绘制等多个精密步骤,每个环节都至关重要。

让我们一同探索浏览器如何将抽象的HTML标签转化为我们所见所闻的丰富网页体验,揭开这一日常数字魔术背后的技术面纱。

本文是参考HTML 渲染那些事儿所著,有需要的小伙伴可以去瞅瞅🚀🚀

页面渲染流程深度解析

页面的基本渲染流程图是:

image.png

1. DOM树的构建

浏览器接收到HTML文档后,会经过以下几个步骤构建DOM树:

  1. 字节转换:网络层传输的字节数据根据编码(如UTF-8)转换为HTML字符串
  2. 令牌化:将HTML字符串解析为令牌(标签名、属性等)
  3. 节点对象创建:将令牌转换为DOM节点对象
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div id = "box">
        <p>Hello , <span>欢迎</span> 来到我的世界 </p>
    </div>
</body>
</html>

上面的HTML对应的DOM节点对象就是下面这种

// HTML元素对应的DOM节点对象表示
{
    type: 'div',
    attrs: {
        id: 'box'
    },
    children: [
        {
            type: 'p',
            children: [
                {
                    type: 'span'
                }
            ]
        }
    ]
}
  1. 构造 DomTree:构造文档对象模型的最后一步就是构建 DomTree。

生成的DomTree如下所示:

image.png

DOM树采用树形数据结构,使得查找和操作非常高效,为后续渲染提供了基础。

2. CSSOM树的构建

与DOM树并行,浏览器会解析CSS样式表,构建CSS对象模型(CSSOM)树。CSSOM包含了所有CSS规则及其层级关系。

这里我了解到的信息是页面加载link外部的css样式的时候,这个时候是不会阻塞DOM Parse的。 它可以一边加载style样式,一边解析DOM,也就是所谓的并行。

但是加载完style样式也需要解析css样式,也就是生成cssom的时候,这个也需要在主进程里面进行,这样就会抢占主线资源,也就是parse css 和 parse html 并不能同时进行。

那为什么css也需要树状结构,因为 Css 的规则是支持“向下级联”的嵌套方案的,也就是我们在日常开发中 Css 的继承特性

3. 渲染树(Render Tree)的生成

DOM树和CSSOM树结合生成渲染树,渲染树只包含需要显示的节点及其样式信息。

这里要注意:不可见元素并不代表不能被看到的元素。比如 visibility: hidden 不同于 display: none. 前者使元素不可见,但元素在布局中仍然占据空间(渲染为空框),而后者display: none表示将元素从渲染树中完全移除,使元素不可见从而不是布局的一部分。

4. 布局(Layout / Reflow)

布局(也称为 Reflow)是浏览器计算 DOM 元素的几何信息(位置、大小等)的过程。

关键步骤

  1. 盒子模型计算

    • 浏览器根据 CSS 计算每个元素的 widthheightpaddingbordermargin 等。
    • 例如,box-sizing: border-box 会影响 width 的计算方式。
  2. 文档流布局

    • 正常流(Normal Flow) :块级元素垂直排列,行内元素水平排列。
    • 浮动(Float) :脱离正常流,其他元素环绕它布局。
    • 绝对定位(Absolute/Fixed) :脱离文档流,相对于最近的非 static 父元素或视口定位。
  3. BFC(块级格式化上下文)

    • 触发条件:overflow: hiddenfloatposition: absolute/fixeddisplay: inline-block 等。
    • 作用:防止外边距折叠(margin collapse),隔离浮动元素的影响。
  4. Flexbox / Grid 布局

    • 现代布局方式,浏览器需要计算 flex 或 grid 容器的子元素排列方式。

触发布局(Reflow)的情况

  • 修改 DOM 结构(增删节点)
  • 改变元素尺寸(widthheightpaddingmargin
  • 改变窗口大小(resize 事件)
  • 读取某些布局属性(如 offsetWidthoffsetHeight

优化建议

  • 避免频繁修改样式,尽量使用 transform 或 opacity(不触发 Reflow)。
  • 使用 requestAnimationFrame 批量修改 DOM。

5. 图层(Layers)处理

浏览器会将某些元素提升为 独立的合成层(Compositing Layer) ,由 GPU 加速渲染,提高性能。

哪些情况会创建新图层?

  1. transform: translate3d() / transform: translateZ(0)

    • 强制 GPU 加速,常用于优化动画性能。
  2. position: fixed / position: absolute + z-index

    • 固定定位或绝对定位的元素可能被提升为独立层。
  3. opacity < 1

    • 半透明元素可能被单独合成。
  4. will-change: transform/opacity

    • 提前告诉浏览器该元素可能会变化,优化渲染。
  5. video / canvas / iframe

    • 浏览器默认会为这些元素创建独立层。

图层的作用:

  • 减少重绘(Repaint) :修改某个图层时,不影响其他图层。
  • GPU 加速:某些变换(如 transformopacity)由 GPU 处理,比 CPU 渲染更快。

优化建议

  • 合理使用 transform 和 opacity 做动画,减少 width/height 变化。
  • 避免滥用 z-index,防止层爆炸(太多图层消耗内存)。

6. 绘制(Painting)

绘制阶段将布局计算后的元素转换成屏幕上的像素。

关键步骤:

  1. 生成绘制指令(Paint Records)

    • 浏览器将元素分解为绘制命令(如“画矩形”、“填充颜色”)。
  2. 光栅化(Rasterization)

    • 将矢量图形(如 CSS 形状)转换成位图(像素)。
    • 通常由 GPU 加速,特别是 transform 和 opacity 变化时。
  3. 合成(Compositing)

    • 将所有图层(Layers)按 z-index 顺序合并成最终图像。

触发重绘(Repaint)的情况:

  • 修改颜色(colorbackground-color
  • 修改边框样式(border-style
  • 修改阴影(box-shadow
  • 修改 opacity(不触发 Reflow,但会 Repaint)

优化建议

  • 使用 transform 和 opacity 做动画,避免触发重绘。
  • 减少复杂的 CSS 选择器,提高绘制效率。

结论

通过深入分析浏览器渲染流程,我们可以清晰地看到,从输入URL到页面呈现是一个由多个精密环节构成的复杂过程。这个过程就像一场精心编排的交响乐,每个步骤都至关重要且环环相扣:

  1. 解析与构建阶段:DOM树和CSSOM树的并行构建展现了浏览器的高效处理能力,而渲染树的生成则体现了样式与结构的完美融合。
  2. 布局计算阶段:浏览器通过复杂的几何计算确定每个元素的精确位置和尺寸,各种布局模式(如Flexbox、Grid)的引入极大地丰富了网页布局的可能性。
  3. 渲染优化阶段:图层处理和GPU加速技术使得现代网页能够实现流畅的动画效果,同时保持高性能。
  4. 绘制呈现阶段:最终通过光栅化和合成将抽象的代码转化为用户可见的像素,完成从数字信息到视觉体验的转换。

这场"数字魔术"的背后,是浏览器工程师们数十年的技术积累和创新。随着Web技术的不断发展,浏览器渲染流程仍在持续优化,为开发者提供更强大的能力,为用户带来更流畅的体验。