浏览器渲染原理

方木先生
    分享互动规则

    每次你打开一个网页,浏览器都在飞速完成一条"流水线"——把你写的 HTML/CSS/JS 变成屏幕上一个个可见的像素。理解这条流水线,是写出高性能前端的基础。


    第一步:解析(Parse)

    浏览器收到服务器返回的 HTML 字节流后,做两件事:

    构建 DOM 树:解析 HTML 标签,形成一棵节点树(Document Object Model)。遇到 <script> 标签,默认会暂停解析,等 JS 执行完再继续——这就是为什么 <script> 要放在 </body> 前,或加 defer / async 属性。

    构建 CSSOM 树:解析所有 CSS(外部文件、<style> 标签、内联样式),构建 CSS Object Model。CSS 是"阻塞渲染"的——CSSOM 没建完,浏览器不会开始渲染。> 开发者须知display: none 的元素不会出现在渲染树里;visibility: hidden 会占位但不显示;opacity: 0 完全可见但透明——三者对渲染流水线的影响完全不同。


    第二步:样式计算(Style)

    浏览器将所有 CSS 规则"匹配"到 DOM 节点上,计算出每个节点最终生效的样式(Computed Style)。这里有几个关键点:

    • 级联(Cascade):多条规则冲突时,按优先级(!important > 内联 > ID > 类 > 标签)决定胜者
    • 继承(Inheritance)font-sizecolor 等属性会从父节点向子节点传递
    • 相对值转绝对值emrem%vh 全部在这一步转换成像素值

    第三步:布局(Layout / Reflow)

    拿到渲染树和每个节点的样式后,浏览器要算出每个元素的几何信息:在页面上的位置 (x, y) 和尺寸 (width, height)。这个过程也叫 Reflow(回流)典型的强制同步布局(性能杀手)

    // ❌ 错误示范:在循环里交替写/读布局属性
    for (let i = 0; i < items.length; i++) {
      items[i].style.width = container.offsetWidth + 'px' // 读 → 触发回流 → 写 → 循环
    }
    
    // ✅ 正确做法:先读后写,批量操作
    const w = container.offsetWidth  // 只读一次
    for (let i = 0; i < items.length; i++) {
      items[i].style.width = w + 'px'
    }
    

    第四步:分层(Layer)

    布局完成后,浏览器会把页面划分成多个图层(Layer)。并非所有元素都是独立图层,只有满足特定条件的元素才会被"提升":

    • transform / opacity 动画的元素
    • position: fixed 的元素
    • will-change 属性的元素
    • <video><canvas><iframe>

    图层的意义在于:某个图层发生变化时,只需重新处理该图层,其他图层不受影响。


    第五步:绘制(Paint / Repaint)

    浏览器遍历每个图层,将元素转换成绘制指令列表(Draw calls),例如"在坐标(x,y)画一个圆角矩形,颜色 #fff,边框 1px #eee"。这个过程叫 Repaint(重绘)

    重绘比回流便宜,但修改 colorbackgroundbox-shadow 等视觉属性都会触发它。---

    第六步:合成(Composite)

    各个图层的绘制指令发送给 GPU,在独立的合成线程(Compositor Thread)上完成最终的像素合成输出到屏幕。

    这一步完全绕开了主线程!这意味着:transformopacity 做动画,即使主线程卡住,动画依然流畅。 这是 CSS 动画优于 JS 动画的核心原因之一。


    实战建议:写出"渲染友好"的代码---

    小结

    阶段做了什么触发条件
    解析HTML → DOM,CSS → CSSOM首次加载,JS 修改 DOM
    样式计算匹配规则,算 Computed Style样式表/类名变化
    布局算坐标和尺寸几何属性改变
    分层划分合成图层特殊 CSS 属性
    绘制生成绘制指令视觉属性改变
    合成GPU 合并图层输出每一帧都发生

    核心结论:优化渲染性能的本质,就是尽量让变化只走流水线的后半段(合成),避免触发回流——因为回流会让整条流水线从布局重头跑一遍。

    评论 0

    支持 @用户名 提醒对方(需为站内已注册用户名);回复仅支持一层楼中楼。

    登录后发表评论、回复与 @ 提及。

    举报

    举报会匿名发送给管理员审核。

    • 暂无评论,来发表第一条。

    码谱 · The Digital Atelier · 技术内容社区