CSS 选择器优先级
1. 概念
当多个 CSS 规则集同时作用于同一个 HTML 标签时:
- 不同属性会叠加
- 相同属性会发生覆盖
在发生覆盖时:
- 如果多个选择器优先级一样,则以写在后面的选择器中的属性为主
- 如果选择器优先级不一样,则以选择器优先级最高那个选择器中的属性值为主
2. 单个选择器类型的权重
2.1 权重值系统
不同类型的选择器有不同的分数值,分数值越高,选择器的权重越高。
| 选择器的类型 | 实例 | 选择器权重 | 等级 |
|---|---|---|---|
| !important | div{ color:red!important; } | 无穷大 | 特级 |
| 行内样式 | style='color:red;' | 1000 | 第一等级 |
| ID 选择器 | #id | 0100 | 第二等级 |
| class、伪类、属性选择器 | .box, :hover, [type='text'] | 0010 | 第三等级 |
| 标签选择器、伪元素选择器 | div, ::after, ::before | 0001 | 第四等级 |
| 通配符、子选择器、相邻选择器等 | *, >, +, ~ | 0000 | 第五等级 |
| 继承的样式 | - | 0000 | - |
提示:
- 通配符
*权重实际是要大于继承的样式的 - 权重值只是相对概念,不能相加后进位
2.2 基础选择器优先级
基础选择器优先级从高到低:
- ID 选择器 > Class 选择器 > 标签选择器 > 通配符选择器
3. 复杂选择器优先级计算
3.1 计算规则
优先级就是分配给指定的 CSS 声明的一个权重
选择器的优先级是由选择器中的每一种选择器类型的数值(权值)相加的最终结果来决定。(数值越大,代表选择器的优先级越高)
权重计算表
| 选择器 | 千位 | 百位 | 十位 | 个位 | 优先级 |
|---|---|---|---|---|---|
| 行内样式 | 1 | 0 | 0 | 0 | 1000 |
div p | 0 | 0 | 0 | 2 | 0002 |
#box div p | 0 | 1 | 0 | 2 | 0102 |
.box .item h3 | 0 | 0 | 2 | 1 | 0021 |
.box:hover p | 0 | 0 | 2 | 1 | 0021 |
3.2 案例分析
案例 1: 相同优先级
问题: 鼠标放在 p 标签上,文字会变成红色吗?
/* 优先级 0011 */
p:hover {
color: red;
}
/* 优先级 0011 */
.box p {
color: blue;
}<body>
<div class="box">
<p>文本内容</p>
</div>
</body>答案: 鼠标滑动到 p 上面,文字并不会变成红色
原因: 两选择器优先级相同,都是 0011,则以写在后面的为主,相同属性发生覆盖。则最终效果为 blue 蓝色,鼠标滑上去文字并不会变色。
案例 2: 不同优先级
问题: 以下案例中的 p 标签的最终显示效果怎样的?
/* 优先级:100 */
#title {
color: red; /* 生效 */
}
/* 优先级:20 */
.box .title {
color: blue; /* 不生效,以#title为主 */
}
/* 优先级:10 */
.title {
font-size: 16px; /* 生效 */
}
/* 优先级:2 */
div p {
font-size: 40px; /* 不生效,以.title中为主 */
}<body>
<div class="box">
<p id="title" class="title">p中内容</p>
</div>
</body>最终效果:
color: red(ID 选择器优先级最高)font-size: 16px(.title优先级高于div p)
案例 3: 多层嵌套优先级
问题: 以下案例中,p 标签中的文字最终是以什么颜色显示?
/* 优先级 0201 */
#box1 #box2 p {
color: red;
}
/* 优先级 0212 - 三个中优先级最高,则以他为主 */
#box1 div.box2 #box3 p {
color: green;
}
/* 优先级 0031 */
.box1 .box2 .box3 p {
color: blue;
}<body>
<div class="box1" id="box1">
<div class="box2" id="box2">
<div class="box3" id="box3">
<p>我是一个段落标签</p>
</div>
</div>
</div>
</body>最终效果: 绿色,因为 #box1 div.box2 #box3 p 优先级最高(0212)
4. 优先级计算注意事项
4.1 不允许进位
在进行选择器权重计算时不允许进位
例如,20 个类选择器仅仅意味着 20 个十位,而不能视为两个百位,也就是说,无论多少个类选择器的权重叠加,都不会超过一个 ID 选择器。
#box {
/* 优先级 0100 */
}
/* 以下 20 个类选择器的权重都是要比 #box 选择器的权重要低 */
.item.item2......item20 {
/* 优先级 0020,仍然低于 ID 选择器 */
}4.2 优先级计算技巧
在比较选择器优先级时,如果都要计算出每个选择器优先级权重值,再来决定优先级高低,那肯定相当麻烦。
推荐一个又快又好的计算优先级的方法:
先比较高位,再比较低位
先比较 ID 选择器,再比较 class、伪类、属性选择器选择器,再比较 标签、伪元素选择器选择器
如果 ID 选择器个数不一样,则以 ID 选择器个数多的为主
- 如果个数一样,则再比较 class、伪类、属性选择器加起的个数
如果 class 选择器个数不一样,则以 class 选择器多的为主
- 如果个数一样,则往后再比较标签、伪元素选择器加起来的个数
- 原理和 ID 选择器比较一样,依此类推
示例 1: ID 选择器比较
/* 先比较两者中的 ID 选择器个数 */
/* 第一个选择器中 ID 个数为 1,第二个为 0,则以 #box 中的样式为主 */
#box {
/* ID 个数: 1 */
}
.item p {
/* ID 个数: 0 */
}结果: #box 优先级更高
示例 2: 相同 ID,比较标签
/* 两者中 ID 个数一样,则比较 class 类 */
/* 类也一样为 0,则比较标签 */
/* 标签个数也一样,则两者优先级一样 */
/* 优先级一样,谁在后面听谁的 */
#box p {
/* ID: 1, Class: 0, 标签: 1 */
}
div p#title {
/* ID: 1, Class: 0, 标签: 2 */
}结果: 第二个选择器优先级更高(标签更多)
示例 3: 比较 class 选择器
/* ID 个数都为 0,则比较 class 类 */
/* 第一个有 2 个 class,第二个只有一个 class */
/* 所以第一个选择器优先级要高,以第一个为主 */
.box .item p {
/* ID: 0, Class: 2, 标签: 1 */
}
.box div p {
/* ID: 0, Class: 1, 标签: 2 */
}结果: 第一个选择器优先级更高(class 更多)
5. !important 提升权重
5.1 !important 的作用
当在一个样式声明中使用一个 !important 规则时,此声明将覆盖任何其他声明,包括行内样式。
虽然,从技术上讲,!important 与优先级无关,但它与最终的结果直接相关。
示例
div {
color: red !important;
}
#box {
color: orange;
}<body>
<div style="color: blue">文本内容</div>
</body>结果: 红色,!important 覆盖了行内样式
注意: 只要 CSS 声明属性值后面带 !important,就一定以他为主。
5.2 慎用 !important
不过我们要慎用 !important,因为这会带来样式的冲突。后面某个地方,需要重写这个样式时,会发现根本无效。一般你在利用第三方组件或 CSS 框架时,如果不能重写样式,那将会失去很多色彩。
某些情况下是可以用的:
- 自定义字体时,
font-family属性后面可以加!important关键字 - 覆盖第三方库的样式
- 紧急修复(临时方案)
6. CSS 选择器冲突解决流程
通过右击审查元素,找到有哪些选择器在控制当前标签元素的样式,然后按以下步骤来分析:
6.1 冲突解决步骤
是否找不到自己写的 CSS 选择器
- 如果是,则肯定是选择器单词写错造成
看元素要生效的样式是否被其它样式覆盖了
属性后面书写了
important关键词- 如果是,去掉
important
- 如果是,去掉
元素是否有添加行内样式,被行内样式覆盖了
- 如果是,则将行内样式改为内联或外链样式
选择器优先级问题造成的覆盖
- 如果是优先级,则提升优先级
书写顺序问题造成的覆盖
- 如果是书写顺序,则调整书写顺序
6.2 常见冲突场景
场景 1: 样式不生效
.box {
color: red;
}
.box {
color: blue; /* 后写的覆盖先写的 */
}结果: 蓝色
场景 2: 优先级不足
p {
color: red;
}
.content p {
color: blue;
}结果: 蓝色(优先级 11 > 1)
场景 3: 悬停效果不生效
/* 优先级 12 */
li a:hover {
color: yellow;
}
/* 优先级 12 */
.list li a {
color: orange;
}结果: 橙色,鼠标滑上去文字不会变成黄色
解决: 提高悬停选择器的优先级
.list li a:hover {
color: yellow;
}7. 实战练习
练习 1: 计算优先级
计算以下选择器的优先级:
/* 选择器 1 */
body div p { }
/* 选择器 2 */
.container .item p { }
/* 选择器 3 */
#main .content p { }
/* 选择器 4 */
div p:hover { }答案:
- 选择器 1: 0002 (2 个标签)
- 选择器 2: 0020 (2 个类 + 1 个标签)
- 选择器 3: 0110 (1 个 ID + 1 个类 + 1 个标签)
- 选择器 4: 0011 (1 个类 + 2 个标签)
练习 2: 最终颜色
以下 span 中文字的颜色是?
.col {
color: red;
}
div p span {
color: blue;
}<body>
<div>
<p><span>span标签的文字颜色</span></p>
</div>
</body>答案: 蓝色,因为 .col 并没有作用于 span 标签
练习 3: 悬停效果
鼠标滑动到 a 标签,a 标签中文字能不能变成黄色?
/* 12 */
li a:hover {
color: yellow;
}
/* 12 */
.list li a {
color: orange;
}<body>
<ul class="list">
<li><a href="">艾编程</a></li>
</ul>
</body>答案: 不能,li a:hover 与 .list li a 的优先级一样,以写在后面的为主,则鼠标滑上去,文字不会变成黄色
练习 4: 后代与子代
以下 li 中和 a 中的文字颜色分别?
/* 2 */
ul li {
color: red;
}
/* 2 */
ul > li {
color: orange;
}<body>
<ul class="list">
<li>点击进入<a href="">艾编程</a></li>
</ul>
</body>答案: 橘黄色,ul li 和 ul > li 的优先级是一样的,以写在后面的为主
8. 最佳实践
8.1 避免过度嵌套
/* ❌ 不推荐: 过度嵌套,难以覆盖 */
.container .sidebar .widget .title {
color: red;
}
/* ✅ 推荐: 使用简洁的类选择器 */
.widget-title {
color: red;
}8.2 使用类选择器为主
/* ❌ 不推荐: 过度使用 ID 选择器 */
#header {
color: blue;
}
#header .nav {
color: white;
}
/* ✅ 推荐: 使用类选择器 */
.header {
color: blue;
}
.header .nav {
color: white;
}8.3 保持选择器简洁
/* ❌ 不推荐: 过于复杂的选择器 */
div ul li a span.highlight {
color: red;
}
/* ✅ 推荐: 简洁的选择器 */
.highlight {
color: red;
}8.4 利用 BEM 命名法
/* 块 */
.card {
background: white;
}
/* 元素 */
.card__title {
font-size: 1.5em;
}
/* 修饰符 */
.card--primary {
border: 2px solid #007bff;
}9. 总结
CSS 选择器优先级关键要点:
权重系统:
- !important: 无穷大
- 行内样式: 1000
- ID 选择器: 100
- class/伪类/属性选择器: 10
- 标签/伪元素选择器: 1
- 通配符/关系选择器: 0
- 继承的样式: 0
计算方法:
- 各选择器类型权重相加
- 不允许进位
- 先比高位(ID),再比低位
计算技巧:
- 先比较 ID 选择器个数
- 再比较 class 选择器个数
- 最后比较标签选择器个数
!important:
- 最高优先级
- 慎用,避免样式冲突
冲突解决:
- 检查选择器是否正确
- 计算优先级
- 调整书写顺序
- 提升优先级或使用 !important
最佳实践:
- 避免过度嵌套
- 使用类选择器为主
- 保持选择器简洁
- 利用 BEM 命名法