前端analysis | What,Why,Who,When,Where,How

css Rule tree

20205-05-05


🌳 什么是 Rule Tree?

Rule Tree 是浏览器在构建 CSSOM 时的一部分结构,它组织了 CSS 中的所有规则(Rule),即每一个选择器+声明组合的结构体。

它的作用是:把从不同来源(内部、外部、继承)来的规则,按“层叠规则(Cascading Rules)”归并起来,为后续匹配和计算样式做准备。


🧩 Rule Tree 的结构本质(简化版)

每个 Rule 节点代表一条规则:

1
2
3
4
5
6
7
8
9
10
{
"selector": "div.main",
"declarations": [
{ "property": "color", "value": "red" },
{ "property": "font-size", "value": "16px" }
],
"origin": "author", // 来源(浏览器、用户、作者)
"important": false, // 是否有 !important
"specificity": [0, 1, 1] // 优先级(ID数、类数、标签数)
}

🔁 Rule Tree 是怎么“合并规则”的?

假设我们有如下三条规则:

1
2
3
4
5
6
7
8
9
10
11
12
/* 默认浏览器样式 */
p {
color: black;
}

/* 外部样式表 */
p {
color: red;
}

/* 内联样式 */
<p style="color: blue;">

浏览器处理的顺序:

来源 优先级高低 说明
浏览器默认(user agent) 最低 最后被覆盖
作者样式表(外部CSS) 中等 一般使用的样式
行内样式 style="" 写的样式
!important 最高 无视一般优先级

按选择器 + 来源 + specificity + 是否 important 区分不同规则 , 浏览器会将匹配到的多条规则收集到一个集合,然后根据这些因素合并:
多个 CSS 规则可能匹配同一个元素时,浏览器必须选出“赢家”,这个过程称为层叠(cascading)。

💡 合并规则优先级判断标准:

  1. !important 有无
  2. 来源(user / author / user-agent)
  3. specificity(选择器的具体程度)
  4. 声明的先后顺序

📚 举个合并例子

1
2
3
4
5
6
7
8
/* style1.css */
p { color: red; }

/* style2.css */
p { color: green !important; }

/* 页面上: */
<p style="color: blue;">Hello</p>

最终谁胜出?

  1. color: blue(内联) specificity 高
  2. color: green !important 是重要声明

最终显示颜色为绿色(因为 !important 胜出)。


🔍 浏览器内部:如何构造 Rule Tree?

浏览器内部通常会用如下数据结构:

1
2
3
4
5
6
CSSRule
└─ Selector (p)
└─ Declarations (color: red)
└─ Specificity (0,0,1)
└─ Origin (author)
└─ Important (false)

Rule Tree 并不是对 DOM 树的映射,而是对选择器规则集合的映射,它将这些规则组合、排序、归类以便查找和比较。


🛠️ 现代浏览器优化:Rule Tree + Style Sharing

像 Firefox 的 Gecko 和 Chrome 的 Blink 引擎,会:

  • 使用“Rule Tree”缓存共享规则,避免重复样式计算
  • 使用“Computed Style”缓存结果,优化性能

✅ 总结:Rule Tree 如何区分和合并规则?

步骤 说明
区分 按选择器 + 来源 + specificity + 是否 important 区分不同规则
合并 把所有匹配同一元素的规则,按层叠规则合并
输出 得出一个元素的最终“计算样式”(Computed Style)

具体拆解你提到的这四个关键维度:选择器 + 来源 + specificity + 是否 !important 是如何让浏览器区分并决定“哪条 CSS 规则最终生效”的。


🧠 背景:多个 CSS 规则可能匹配同一个元素时,浏览器必须选出“赢家”,这个过程称为层叠(cascading)


✅ 四大决策因子详解

选择器(Selector)

哪个选择器能匹配当前元素?可能匹配上多个,例如:

1
2
3
div { color: red; }
#main { color: green; }
div#main { color: blue; }

这些都会匹配 <div id="main">,但最终只能取其中一个。


来源(Origin)

CSS 有三种来源,优先级不同:

来源 权重(从低到高)
User agent(浏览器默认) 最低
用户样式(用户设置) 中(通常可被覆盖)
作者样式(网站写的) 高(一般我们写的 CSS)
!important 版本 会覆盖上面所有

例如:

1
2
3
4
5
6
7
8
/* 浏览器默认 */
body { font-size: 16px; }

/* 作者样式 */
body { font-size: 20px; }

/* 用户设置 */
body { font-size: 18px !important; } <-- 覆盖作者样式

Specificity(选择器优先级)

浏览器给选择器打“分”,越具体,分越高,越容易胜出:

选择器类型 分值表示形式(a,b,c,d) 举例 说明
!important 特殊处理,最高 特例,详见下一项
行内样式(style) 1,0,0,0 style="..." 优先级高于任何选择器
ID 选择器(#id) 0,1,0,0 #header 高优先级
类、属性、伪类选择器 0,0,1,0 .box, [type=] 常见
元素、伪元素选择器 0,0,0,1 div, p, ::after 优先级最低

示例

1
2
3
4
5
6
7
8
/* specificity: (0,0,0,1) */
p { color: red; }

/* specificity: (0,0,1,0) */
.text { color: green; }

/* specificity: (0,1,0,0) */
#main { color: blue; }

优先级从高到低:#main > .text > p


是否有 !important

这相当于“加特权”:

1
2
3
.box {
color: red !important;
}

即使 .box 的 specificity 低于其他规则,它也会胜出。

但是:多个 !important 要比 specificity!

1
2
3
4
5
6
.box {
color: red !important; /* specificity: 0,0,1,0 */
}
#main {
color: blue !important; /* specificity: 0,1,0,0 */
}

#main 的规则胜出,因为 !important 且 specificity 更高。


🎯 决策流程图(简化文字版)

1
2
3
4
5
是否有 !important?
├── 是 → specificity 高者胜出
├── 否 → 来源高者胜出(作者 > 用户 > 浏览器)
└── 若来源相同 → specificity 高者胜
└── 若 specificity 相同 → 后写的覆盖前写的

🧪 实战举例分析

HTML:

1
<div id="main" class="box" style="color: orange;">Hello</div>

CSS:

1
2
3
4
5
6
7
8
9
10
11
/* specificity: 0,0,1,0 */
.box {
color: red;
}

/* specificity: 0,1,0,0 */
#main {
color: green;
}

/* inline style, specificity: 1,0,0,0 */

→ 谁胜出?

最终颜色是:橙色(来自 inline style


加一条:

1
2
3
.box {
color: purple !important;
}

→ 此时颜色是:紫色(因为 !important 胜出,即使 specificity 低)


使用支付宝打赏
使用微信打赏

若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏