什么是CSSOM?

CSSOM(CSS Object Model,CSS对象模型)是浏览器解析CSS后构建的对象树结构。它与DOM(Document Object Model)类似,但专门用于存储样式信息。CSSOM是浏览器渲染流程中的关键步骤之一。

CSSOM的作用

  • 样式解析:将CSS文本解析为浏览器可理解的规则
  • 样式匹配:将样式规则匹配到对应的DOM节点
  • 样式计算:计算每个元素的具体样式属性值
  • 渲染准备:为Render Tree的生成提供必要数据

CSSOM工作流程

CSS文本
词法分析
语法分析
CSSOM树

CSSOM构建过程

CSSOM构建步骤

步骤 名称 描述 输入 输出
1 CSS解析 将CSS文本解析为CSS规则 CSS文件/样式表 CSS规则
2 选择器匹配 从右向左匹配选择器 DOM节点 匹配的规则
3 样式计算 计算最终样式值 继承规则 计算样式
4 CSSOM构建 组织成树结构 所有规则 CSSOM树

1. CSS解析

浏览器收到CSS文件后,首先进行词法分析和语法分析,将CSS文本解析为CSS规则。

/* 原始CSS */ .container { width: 100%; max-width: 1200px; margin: 0 auto; } .header { background: #fff; padding: 20px; } /* 解析为CSSOM */ CSSOM = [ { selector: '.container', declarations: [ { property: 'width', value: '100%' }, { property: 'max-width', value: '1200px' }, { property: 'margin', value: '0 auto' } ] }, { selector: '.header', declarations: [ { property: 'background', value: '#fff' }, { property: 'padding', value: '20px' } ] } ]

2. 选择器匹配

浏览器从右向左匹配选择器,为每个DOM节点找到匹配的CSS规则。

选择器类型对比

选择器类型 语法 优先级 示例
ID选择器 #id ⭐⭐⭐⭐⭐ #header
类选择器 .class ⭐⭐⭐ .container
标签选择器 element div
属性选择器 [attr] ⭐⭐ [type="text"]
伪类选择器 :pseudo ⭐⭐ :hover

3. 样式计算

对于每个DOM节点,浏览器会计算其最终的样式属性值,考虑继承和层叠规则。

样式继承对比

属性类型 是否继承 示例属性
文本属性 ✅ 继承 color, font-size, line-height
列表属性 ✅ 继承 list-style, list-style-type
盒模型属性 ❌ 不继承 width, height, padding, margin
定位属性 ❌ 不继承 position, top, left
背景属性 ❌ 不继承 background, background-color

4. CSSOM树构建

最终,浏览器会将所有匹配的样式信息组织成CSSOM树结构。

/* CSSOM树结构示例 */ CSSOM { '.container': { 'width': '100%', 'max-width': '1200px', 'margin': '0 auto', 'padding': '20px', 'background': '#fff' }, '.header': { 'background': '#fff', 'padding': '20px', 'color': '#333' }, '.content': { 'font-size': '16px', 'line-height': '1.6', 'color': '#666' } }

DOM与CSSOM的合并

DOM和CSSOM是两个独立的数据结构,它们最终会合并生成Render Tree。

合并流程图

DOM树
HTML结构
CSSOM树
样式规则
样式匹配
DOM节点 + CSSOM样式
样式计算
继承 + 层叠
Render Tree
可见节点 + 最终样式

DOM与CSSOM对比

特性 DOM CSSOM
数据来源 HTML文档 CSS样式表
存储内容 节点结构、文本内容 样式规则、属性值
构建时机 HTML解析时 CSS解析时
独立性 独立构建 独立构建
最终作用 提供页面结构 提供样式信息

合并过程

  1. 浏览器从DOM树的根节点开始
  2. 对于每个DOM节点,在CSSOM中查找匹配的样式
  3. 将样式信息附加到DOM节点上
  4. 计算每个节点的最终样式值
  5. 只保留可见节点(display: none的节点被排除)
/* DOM节点 */
标题
内容
/* 匹配的样式 */ .container { width: 100%; max-width: 1200px; margin: 0 auto; } .header { background: #fff; padding: 20px; } .content { font-size: 16px; line-height: 1.6; } /* 合并后的Render Tree节点 */ Node: div.container - width: 100% - max-width: 1200px - margin: 0 auto - background: #fff (继承) - color: #333 (继承) Node: header.header - background: #fff - padding: 20px - color: #333 (继承) Node: div.content - font-size: 16px - line-height: 1.6 - color: #666

Render Tree生成过程

Render Tree生成流程

1. 从DOM根节点开始
2. 可见性判断
3. 样式附加
4. Render Tree构建

可见性判断规则

CSS属性 是否包含在Render Tree 是否占用布局空间 是否可交互
display: none ❌ 不包含 ❌ 不占用 ❌ 不可交互
visibility: hidden ✅ 包含 ✅ 占用 ❌ 不可交互
opacity: 0 ✅ 包含 ✅ 占用 ✅ 可交互
默认 ✅ 包含 ✅ 占用 ✅ 可交互

1. 从DOM根节点开始

浏览器从DOM树的根节点(通常是)开始遍历。

2. 可见性判断

对于每个DOM节点,判断其是否需要在屏幕上渲染:

不可见的节点

  • display: none:完全不可见,不占用布局空间
  • visibility: hidden:不可见但占用布局空间
  • opacity: 0:完全透明但可交互

3. 样式附加

为每个可见节点附加从CSSOM中获取的样式信息。

4. Render Tree构建

最终生成Render Tree,它只包含可见的节点及其样式信息。

/* DOM树 */ ...
标题
内容
隐藏元素
/* Render Tree(排除了display: none的节点) */ Node: html Node: body Node: div.container - width: 100% - max-width: 1200px - margin: 0 auto Node: header.header - background: #fff - padding: 20px Node: div.content - font-size: 16px - line-height: 1.6 /* 注意:隐藏元素被排除在Render Tree之外 */

布局与重排

布局计算流程

1. 计算父容器尺寸
2. 计算子元素位置
3. 计算元素尺寸
4. 处理浮动和定位

布局计算

有了Render Tree后,浏览器开始计算布局(Layout),确定每个元素在页面上的位置和大小。

布局计算步骤

  1. 计算父容器尺寸:从根元素开始,逐步计算每个容器的尺寸
  2. 计算子元素位置:根据定位属性(static、relative、absolute、fixed)确定位置
  3. 计算元素尺寸:根据内容、padding、border、margin等计算尺寸
  4. 处理浮动和定位:处理float、position等特殊布局

重排触发条件

当页面结构或样式发生变化时,可能需要重新计算布局,这个过程称为重排(Reflow)。

重排触发条件

操作类型 具体操作 影响范围
DOM操作 添加/删除DOM节点 全局
位置修改 修改top、left、bottom、right 局部
尺寸修改 修改width、height、padding、margin、border 局部/全局
内容修改 文本变化导致尺寸变化 局部
显示属性 修改display属性 全局
定位属性 修改position属性 全局
浮动属性 修改float属性 全局

避免重排的技巧

  • 使用transform代替top/left进行动画
  • 使用opacity代替display: none实现显隐
  • 批量操作DOM(使用DocumentFragment)
  • 为频繁变动的元素设置position: absolutefixed

绘制与重绘

绘制流程

1. 分层(Layering)
2. 栅格化(Rasterization)
3. 合成(Compositing)

绘制过程

布局计算完成后,浏览器开始绘制(Paint),将每个节点的样式绘制到屏幕上。

/* 绘制流程 */ 1. 分层(Layering):将元素分层处理 2. 栅格化(Rasterization):将矢量图形转换为像素 3. 合成(Compositing):将各层合并到最终屏幕 /* 示例:一个页面的绘制过程 */ Layer 1: 背景(背景色、背景图片) Layer 2: 文本内容 Layer 3: 装饰元素(阴影、边框) Layer 4: 视频或其他媒体 → 合成所有层到最终屏幕

重绘触发条件

当元素的视觉效果发生变化但不需要重新计算布局时,触发重绘(Repaint)。

重绘触发条件

属性类型 CSS属性 触发类型
颜色属性 color, background-color, border-color 仅重绘
背景属性 background-image, background-position 仅重绘
可见性属性 visibility, opacity 仅重绘
装饰属性 box-shadow, text-shadow 仅重绘
轮廓属性 outline 仅重绘

重绘比重排性能更好

重绘比重排性能更好,因为它不需要重新计算布局。但最佳实践是尽量减少重绘,通过硬件加速(GPU)和图层优化来提升性能。

性能优化

性能优化策略

优化类别 优化方法 具体技巧 性能提升
减少重排 避免布局变化 使用transform代替top/left ⭐⭐⭐⭐⭐
减少重绘 优化视觉效果 使用opacity代替display: none ⭐⭐⭐⭐
批量操作 减少DOM操作 使用DocumentFragment ⭐⭐⭐⭐⭐
选择器优化 提高匹配效率 避免通配符和后代选择器 ⭐⭐⭐
CSS加载 优化加载时机 关键CSS内联,preload预加载 ⭐⭐⭐⭐
硬件加速 使用GPU加速 transform: translateZ(0) ⭐⭐⭐⭐

1. 减少重排和重绘

  • 使用transformopacity进行动画
  • 批量修改DOM,避免多次重排
  • 使用DocumentFragment进行批量插入
  • 使用will-change提示浏览器优化

2. 优化CSS选择器

  • 避免使用通配符选择器*
  • 避免使用后代选择器div p span
  • 使用类选择器代替标签选择器
  • 选择器匹配从右到左,保持选择器简洁

3. 优化CSS加载

  • 将CSS放在<head>中,避免FOUC(无样式内容闪烁)
  • 使用<link rel="preload">预加载关键CSS
  • 使用媒体查询@media加载特定设备的CSS
  • 压缩CSS文件,减少文件大小

4. 使用CSS硬件加速

  • 使用transform: translateZ(0)开启硬件加速
  • 使用will-change: transform提示浏览器
  • 使用backface-visibility: hidden优化3D变换
  • 避免过度使用,增加内存消耗

工具与调试

Chrome DevTools - Performance面板

Performance面板可以录制页面加载过程,分析CSSOM构建、布局计算和绘制过程,识别性能瓶颈。

Chrome DevTools - Layers面板

p>Layers面板可以查看页面的图层结构,分析重排和重绘性能,优化图层创建策略。

Chrome DevTools - Styles面板< p>Styles面板可以查看元素的Computed样式,检查样式的来源和继承关系。

调试技巧

  • 使用document.getComputedStyle()获取计算样式
  • >
  • 使用getBoundingClientRect()获取元素位置信息
  • >
  • 使用PerformanceObserver监控性能指标
  • >
  • 使用MutationObserver观察DOM变化

实际案例

/* HTML结构 */
标题
内容
/* CSSOM构建过程 */ 1. 解析CSS规则 2. 构建CSSOM树 3. DOM与CSSOM合并 4. 生成Render Tree(排除.hidden元素) 5. 布局计算 6. 绘制渲染 /* Render Tree结构 */ Node: html Node: body Node: div.container - width: 100% - max-width: 1200px - margin: 0 auto Node: header.header - background: #fff - padding: 20px Node: div.content - font-size: 16px - line-height: 1.6 /* 注意:.hidden元素被排除 */

性能分析

使用Chrome DevTools的Performance面板录制页面加载,可以看到:

  • Parse HTML:解析HTML构建DOM
  • >
  • Parse Stylesheet:解析CSS构建CSSOM
  • >
  • Recalculate Style:重新计算样式
  • >
  • Layout:布局计算
  • >
  • Paint:绘制渲染
  • Composite:合成显示

常见问题

FAQ - 常见问题解答

问题 答案 相关知识点
CSSOM和DOM有什么区别? DOM存储HTML结构和内容信息,CSSOM存储CSS样式规则。两者独立构建,然后合并生成Render Tree用于渲染。 DOM、CSSOM、Render Tree
为什么CSS解析会阻塞渲染? 浏览器需要完整的CSSOM才能确定每个元素的最终样式,避免样式闪烁。因此CSS解析会阻塞Render Tree的生成,但不会阻塞DOM的构建。 CSSOM构建、渲染阻塞
重排和重绘有什么区别? 重排需要重新计算布局,影响性能较大;重绘只更新视觉效果,不需要重新计算布局,性能开销较小。应该尽量减少重排,优先使用重绘。 布局计算、绘制渲染
如何优化CSS加载性能? 将关键CSS内联在HTML中,使用<link rel="preload">预加载,使用媒体查询加载非关键CSS,压缩CSS文件,减少文件大小。 CSS加载、性能优化
什么是FOUC? FOUC(Flash of Unstyled Content)是页面加载时短暂显示无样式内容的现象。避免方法是将CSS放在<head>中,或使用内联关键CSS。 CSS加载顺序、FOUC

总结

CSSOM完整渲染流程

HTML文档
CSS样式表
DOM树
CSSOM树
Render Tree
布局(Layout)
绘制(Paint)
合成(Composite)
屏幕显示

CSSOM是浏览器渲染流程中的重要组成部分,它将CSS样式转换为浏览器可理解和应用的对象结构。通过理解CSSOM的构建过程、与DOM的合并方式、Render Tree的生成过程,以及重排和重绘的机制,我们可以更好地优化页面性能,提供更流畅的用户体验。

关键要点

  • CSSOM是浏览器解析CSS后构建的对象树
  • DOM和CSSOM独立构建,然后合并生成Render Tree
  • Render Tree只包含可见节点和样式信息
  • 重排比重排性能开销大,应尽量减少
  • 使用现代CSS属性和硬件加速优化性能