个人博客:haichenyi.com。感谢关注
一. 目录
- 一–目录
- 二–页面渲染过程
- 三–DOM树和渲染树
二. 页面渲染过程
浏览器的渲染过程可以分解为以下几个关键步骤
2.1 解析HTML,形成DOM树
- 浏览器从上往下解析HTML文档,将标签转成DOM节点,形成树状结构(DOM tree)
- 遇到外部资源(CSS,图片)会并行下载,但同步的JavaScript会同步下载,阻塞HTML解析,会导致页面显示的慢,让用户体验变差。(为了解决这个问题,可以使用async或者defer属性,具体的功能之前博客中有讲过)
2.2 解析CSS,生成CSSOM树
- 解析CSS样式(包括内联样式和外部样式),生成CSSOM,描述样式的层级关系
- CSSOM树是逐步完成的,浏览器会避免"回溯"以保证效率
2.3 合并DOM和CSSOM,构建渲染树(Render tree)
- 渲染树仅包含可见的DOM节点(display:none的元素会被排除),并为每个节点匹配对应的CSS样式
- 伪元素(::after,::before)等,会以独立节点的形式加入渲染树,DOM节点中不包含这些节点
2.4 布局(Layout/Reflow)
- 结算每个节点的位置和尺寸,确定其在屏幕上的位置
- 布局过程可能会因为窗口大小发生变化,内容调整等因素触发重排(性能敏感操作)(重排与重绘的区别之前讲过了)
2.5 绘制(Painting)与合成(Compositing)
- 将布局后的节点转换为屏幕上的像素,包括文本,颜色,边框等等视觉属性的位置
- 现代浏览器会将页面分层(GPU加速层),分别绘制后,通过合成器合并为最终图像
CSS解析的时候说到了"回溯",什么是"回溯"呢?
简单来说:假设解析器在解析一段CSS的时候,发现某个规则可能与后续规则冲突(例如选择器优先级或继承关系不明确),需要回退到之前解析的状态,尝试另一种解析路径,这种"试错"行为称之为回溯。举个栗子:
/* 假设解析器需要判断 .box 和 .container 的嵌套关系 */
.container .box { color: red; }
.box { color: blue; }
如果解析器先处理了 .box,但后续发现 .container .box 优先级更高,可能需要回退并重新匹配,导致性能损耗。
为什么CSS解析器容易引发回溯?
- 选择器的复杂性:复杂的选择器(嵌套,后代选择器等),可能会导致解析器需要多次确认匹配关系
- 规则优先级冲突:当多个规则作用于同一个元素时,解析器需要计算优先级,可能需要重新遍历规则
- 动态性:某些CSS的规则(如@media媒体查询)依赖外部条件(如试图大小),解析需要重新评估
三. DOM树和渲染树
区别点 | DOM 树 | 渲染树(Render Tree) |
---|---|---|
节点范围 | 所有HTML元素 | 仅包含可见的节点(如display:none会被排除) |
结构差异 | 严格反应HTML元素的层级关系 | 可能合并或者拆分DOM节点(如表格的复杂结构) |
样式处理 | 不存储样式信息,仅表示文档结构 | 每个节点关联样式,确定最终的视觉表现 |
动态更新影响 | 修改DOM会触发后续的重建,布局和绘制 | 修改样式可能仅触发重绘或重排(颜色变化) |
关键总结:
- 渲染树是 DOM 和 CSSOM 的结合产物,决定了页面的视觉呈现。
- DOM 树是基础结构,渲染树是优化后的“渲染蓝图”,两者共同驱动浏览器高效渲染页面。
- 性能优化:减少重排(如批量 DOM 操作)和重绘(如使用 transform 替代 top/left)可提升渲染效率。