CSS 优先级
本教程共 44 篇 · 第 44 篇 · 更新于 2026-07-29 · 约 14 分钟阅读
44. CSS 优先级
本节目标:理解 CSS 层叠规则,掌握特异性计算方法,能够正确处理样式冲突,了解级联层的使用场景。
当多条 CSS 规则作用于同一个元素时,浏览器怎么决定用哪个?这就是优先级(也叫特异性、specificity)要解决的问题。
层叠算法
浏览器处理样式冲突有一套完整的流程:
- 相关性:筛选出匹配当前元素的规则
- 来源和重要性:按来源(浏览器、开发者、用户)和
!important排序 - 特异性:来源相同时,比较选择器的特异性
- 作用域距离:特异性相同时,比较作用域距离
- 出现顺序:以上都相同时,后写的规则胜出
简单说就是:先看点有没有匹配,再看来源和重要性,然后算特异性,最后看谁后写。
来源优先级
CSS 有三大来源,优先级从低到高:
| 来源 | 说明 |
|---|---|
| 浏览器样式(user-agent) | 浏览器默认样式,比如 <h1> 默认加粗 |
| 用户样式(user) | 用户自定义的样式(很少用) |
| 作者样式(author) | 开发者写的样式 |
开发中写的样式都是”作者样式”,优先级高于浏览器默认样式。这就是为什么我们写的 CSS 能覆盖浏览器默认样式。
特异性计算
特异性是一个三元组:(ID数, 类数, 元素数)。比较时从左到右,ID 列权重最高。
| 选择器类型 | 权重 | 示例 |
|---|---|---|
| 行内样式 | 最高 | style="color: red" |
| ID 选择器 | 1-0-0 | #nav |
| 类/属性/伪类 | 0-1-0 | .btn、[type]、:hover |
| 元素/伪元素 | 0-0-1 | div、::before |
| 通配符 | 0-0-0 | * |
计算示例:
h1 /* 0-0-1 → 1 */
.title /* 0-1-0 → 10 */
#nav /* 1-0-0 → 100 */
.content h1 /* 0-1-1 → 11 */
#nav .title /* 1-1-0 → 110 */
#nav .title:hover /* 1-2-0 → 120 */
div#main .title.active /* 1-2-1 → 121 */
<!DOCTYPE html>
<html lang="zh">
<head>
<style>
/* 特异性:0-0-1 = 1 */
p { color: blue; }
/* 特异性:0-1-0 = 10 */
.text { color: green; }
/* 特异性:0-2-0 = 20 */
.text.highlight { color: orange; }
/* 特异性:1-0-0 = 100 */
#special { color: red; }
</style>
</head>
<body>
<p>蓝色(元素选择器)</p>
<p class="text">绿色(类选择器)</p>
<p class="text highlight">橙色(两个类)</p>
<p class="text highlight" id="special">红色(ID 选择器)</p>
</body>
</html>
记忆口诀:ID > 类 > 元素。同一列里数量多的赢。不同列之间,左边的列永远比右边的列重要。
特殊情况
组合器不影响特异性
>、+、~、空格这些组合器本身不计入特异性:
.container p /* 0-1-1 → 11 */
.container > p /* 0-1-1 → 11(一样) */
p + p /* 0-0-2 → 2 */
:is() 和 :not() 的特异性
:is() 和 :not() 本身不计入特异性,但它们参数中特异性最高的那个选择器会计入:
/* 特异性来自 #nav,即 1-0-0 */
:is(#nav, .menu) a /* 1-0-1 → 101 */
/* 特异性来自 .active,即 0-1-0 */
:not(.active) /* 0-1-0 → 10 */
:where() 始终为 0
:where() 会把特异性清零:
/* 特异性为 0-0-0 */
:where(#nav) a { color: red; }
/* 可以用很简单的选择器覆盖它 */
a { color: blue; }
继承的特异性为 0
从父元素继承来的样式,特异性为 0:
/* div 的 color 是 red(直接设置) */
div { color: red; }
/* p 继承 div 的 color,特异性为 0 */
div p { color: blue; } /* 直接选 p,0-0-1 > 0,所以是蓝色 */
/* 但如果是 span 继承 div */
div { color: red; font-size: 20px; }
span { font-size: 16px; } /* span 直接设置 font-size,覆盖继承 */
!important
!important 是优先级中的”王牌”,能覆盖几乎所有规则:
/* 即使 ID 选择器特异性更高,也赢不过 !important */
#title { color: red; }
.title { color: blue !important; } /* 胜出 */
但 !important 也有被覆盖的时候:
/* 后写的 !important 覆盖先写的 !important */
.title { color: blue !important; }
.title { color: red !important; } /* 胜出 */
<!DOCTYPE html>
<html lang="zh">
<head>
<style>
p { color: red !important; }
#special { color: blue; }
.text { color: green; }
</style>
</head>
<body>
<!-- 行内样式 + !important 才能覆盖作者的 !important -->
<p class="text" id="special" style="color: orange !important;">
橙色(行内 !important)
</p>
<p class="text" id="special">
红色(作者 !important 覆盖了 ID 选择器)
</p>
</body>
</html>
不要滥用
。一旦用了,只能用另一个
!important覆盖,形成恶性循环。优先用提高选择器特异性的方式来覆盖。
合理使用场景
- 覆盖第三方库的样式(无法修改源码时)
- 工具类(
.hidden { display: none !important; }) - 用户样式表(无障碍需求)
级联层(@layer)
级联层是 CSS 较新的特性,让你从更高层面控制优先级:
/* 声明层,后面的层优先级更高 */
@layer base, components, utilities;
@layer base {
button {
background: gray;
}
}
@layer components {
.btn-primary {
background: blue;
}
}
@layer utilities {
.bg-red {
background: red;
}
}
层内优先级再高,也抵不过外层(后声明)的普通样式:
@layer base {
/* 特异性 1-0-0,但在层内 */
#title { color: red; }
}
/* 不在层内,优先级高于层内规则 */
.title { color: blue; } /* 胜出 */
<!DOCTYPE html>
<html lang="zh">
<head>
<style>
@layer base, override;
@layer base {
/* 特异性很高,但在 base 层 */
#app .title { color: red; }
}
@layer override {
/* 特异性较低,但在更高优先级的层 */
.title { color: blue; } /* 胜出 */
}
</style>
</head>
<body>
<div id="app">
<h1 class="title">蓝色(来自 override 层)</h1>
</div>
</body>
</html>
级联层特别适合管理大型项目的优先级。把第三方库放到低优先级层,自己写的样式放到高优先级层,从根本上避免冲突。
解决样式冲突的步骤
当发现样式没生效时,按以下步骤排查:
- 检查选择器是否匹配:DevTools 看元素匹配了哪些规则
- 看有没有被划掉:被划掉的样式被更高优先级的规则覆盖了
- 比较特异性:被覆盖的选择器特异性是否低于覆盖它的
- 检查来源:浏览器默认样式、用户样式、作者样式的优先级
- 检查层:是否在级联层中,层的优先级如何
DevTools 的 Styles 面板会清晰展示所有匹配的规则,被覆盖的会显示删除线。
优先级速查表
| 优先级因素 | 影响 |
|---|---|
!important | 提升为最高优先级(作者来源) |
| 行内样式 | 作者来源中最高(除了 !important) |
| 级联层 | 后声明的层优先级更高 |
| 特异性 | ID > 类 > 元素 |
| 出现顺序 | 特异性相同时,后写的胜出 |
| 直接设置 vs 继承 | 直接设置的优先级高于继承 |
最佳实践
不要用 ID 选择器写样式
ID 特异性太高,很难覆盖。用类代替:
/* 不好:特异性 1-0-0,很难覆盖 */
#submit-btn { background: blue; }
/* 好:特异性 0-1-0,容易覆盖 */
.btn-primary { background: blue; }
保持低特异性
特异性越低,越容易被覆盖,组件的可复用性越好:
/* 特异性 0-1-0 */
.card { background: white; }
/* 特异性 0-2-0,用于覆盖 */
.card.highlighted { background: yellow; }
用变量管理主题色
:root {
--primary: #3498DB;
}
.btn {
background: var(--primary);
}
/* 覆盖时只需改变量 */
.btn-danger {
--primary: #E74C3C;
}
调试 CSS 时,先别急着加
。检查选择器特异性、层叠顺序,往往能找到更优雅的解决方案。