CSS优先级按选择器权重计算,不取决于书写顺序;权重由ID、类、元素等数量决定,相等时才看源码顺序;慎用!important和内联样式,推荐用属性选择器、:where()降权或拆分样式表来提升可维护性。

多个CSS选择器作用于同一元素时优先级怎么算
浏览器不是看谁写在后面就听谁的,而是按「选择器权重」计算优先级。比如 .header .nav a 比 a.active 权重高,因为前者有 2 个类选择器 + 1 个元素选择器(0,2,1),后者是 1 个类 + 1 个元素(0,1,1)。权重不等时,高者胜出;相等才看源码顺序。
常见误判点:
- ID 选择器
#nav权重是 (1,0,0),一个顶一百个类,慎用 -
!important不是解药——它会破坏可维护性,且多个!important还要再比权重 - 内联样式
style="color:red"权重是 (1,0,0,0),比所有外部选择器都高,但无法继承、难复用
用属性选择器或伪类替代嵌套类名来降低权重
想让样式更可控,就别堆砌类名。比如原本写 .card .card__title .card__title--large,权重高、语义重复、难调试。换成:
.card [data-role="title"][data-size="large"] {
font-size: 1.5rem;
}
这样权重只有 (0,2,0),比三段类名组合低,也更容易被局部覆盖。同理,:is(.btn-primary, .btn-secondary) 可合并逻辑,但注意 :is() 内部选择器仍各自参与权重计算。
立即学习“前端免费学习笔记(深入)”;
适用场景:
- 组件内部变体多,但不想靠深度嵌套提升权重
- 需要 JS 动态切换状态(如
data-state="loading"),避免反复增删类名 - 第三方库样式干扰时,用
[class~="btn"]精准匹配含某单词的 class 值
用 :where() 或 :has() 主动降权或条件隔离
:where() 的关键特性:括号内选择器不贡献权重。比如:
:where(.legacy-grid .cell) {
padding: 0.5rem;
}
这段实际权重是 0 —— 它不会压过你写的 .cell 单类规则。适合用于重置旧样式、兼容层、或 CSS reset 片段。
:has() 则相反,能做「父级根据子级状态变化」,但要注意它本身不增加权重,真正起作用的是外面那个父选择器。例如:
.post:has(> .post__media) {
margin-bottom: 2rem;
}
这里权重来自 .post,不是 :has()。它解决的是「无法向上选中」的问题,而不是权重冲突。
注意:
-
:where()和:has()在 Safari 15.4+ / Chrome 105+ 才稳定支持,老版本需 fallback -
:has()不能出现在纯 CSS 规则左端以外的位置(比如不能写div:has(p) span中的span部分用:has())
拆分样式表比拆分选择器更治本
选择器组合冲突,本质常是职责混在一起。与其不断调优选择器,不如按「谁该管什么」切文件:
-
base.css:只放重置、字体、颜色变量,全用低权重(元素、属性、伪类) -
components/card.css:只定义.card及其直接子元素,禁止出现.page-main .card -
pages/home.css:只处理页面级布局和例外调整,用 ID 或带命名空间的类(如.home-card)
这样即使某个组件被复用到不同页面,也不会因外层容器类名意外提升权重而失效。真正的难点不在语法,而在团队是否愿意约束「哪里写什么」。










