CSS 层叠与优先级
学 CSS 一定会遇到这个问题,写了半天样式,某个元素就是不变,改来改去没效果。十有八九是层叠的问题,有别的规则比你写的那条更”大”。这一篇把层叠讲透,以后遇到样式不生效,你就有排查思路了。
层叠的实质
一个元素的最终样式,是浏览器从所有可能的来源里挑出来的。来源包括浏览器默认样式、你写的样式,还有可能来自框架或第三方库。它们像几层被子叠在一起,同一条属性被多个来源声明时,浏览器按规则只挑一层生效,这个过程就是层叠。
具体裁定分三步,先比优先级,再比谁写得更靠后,最后比 !important。优先级是第一步,也是最重要的。
优先级计算
优先级由选择器的类型决定,从高到低是固定的。
| 选择器类型 | 优先级等级 | 例子 |
|---|---|---|
| 内联样式 | 最高 | style=”color: red” |
| ID 选择器 | 高 | #main-nav |
| 类、属性、伪类 | 中 | .warning、[href]、:hover |
| 标签、伪元素 | 低 | p、::before |
浏览器内部把它算成一组数字,a 位记 ID 数量,b 位记类和伪类数量,c 位记标签数量,三个数从左到右比大小,a 位大的赢,a 位相同比 b 位,依此类推。不用死记公式,会用就行,关键在组合。两个选择器命中同一个元素,谁更”精确”谁赢。
.title { color: red; } /* b 位 1,c 位 0 */
div .title { color: blue; } /* b 位 1,c 位 1 */
上面第二条赢,因为它多了一个标签选择器的”精确度”。下面这个例子是经典误区。
#box .title { color: red; } /* a 位 1,b 位 1 */
.box .title { color: blue; } /* b 位 2 */
十条蓝色加起来也赢不过一条红色,因为 a 位的 ID 是压倒性的。这就是为什么前面强调,样式能用类就不要用 ID。
源顺序规则
优先级相同怎么办,比出场顺序,写在后边的赢。
p { color: red; }
p { color: blue; }
结果所有 p 都是蓝色。这也是排错的第一思路,样式不生效,先看有没有一条同样权重的规则写在你后面。第三方库的样式经常因为这个把你的样式顶掉,解决方法是把你的文件放在库的后面引入,或者加类名提高权重。
!important 的警示
!important 写在声明值的末尾,作用是跳过优先级和顺序,强制这条声明生效。
p {
color: red !important;
}
听起来很爽,但它会破坏层叠的整个平衡,一旦用上,后面想覆盖它,只能再加 !important,越用越多,最后没人敢动你的代码。规范的建议是,普通开发里不要用,只在两种场景考虑,调试时临时验证,或者覆盖第三方库的样式实在绕不开时。把它当成最后的手段,不是常规武器。
常见误区
内联样式和选择器优先级要分清,内联样式高,不代表它同级的每条声明都压得住 !important。通配符 * 的优先级是零,它写的样式可以被任何其他选择器覆盖。还有继承的值优先级很低,任何一个直接声明都能覆盖继承来的样式,这跟下一篇的内容衔接上了。
小结
层叠三步走,优先级、源顺序、!important。正常写代码,遵守两条就能避开九成问题,优先用类选择器控制权重,同权重时把更重要的样式写后面。下一讲讲继承,它和层叠经常一起出现,是一对好兄弟。