深蓝的天空

一只切图喵的碎碎念

理解 CSS 权重

权重值的计算

在最开始学习 CSS 的时,由于自己对 CSS 权重计算认识还很模糊的,在编码的时候单纯的堆积选择器数量来实现样式覆盖,导致代码非常臃肿不利于维护或者经常会疑惑某条 CSS 规则为何没有生效。正所谓“基础不牢,地动山摇”,今天就来好好回顾回顾 CSS 权重的基础。


其实计算规则在 W3C 规范中有解释:

  1. count 1 if the declaration is from is a 'style' attribute rather than a rule with a selector, 0 otherwise (= a) (In HTML, values of an element's "style" attribute are style sheet rules. These rules have no selectors, so a=1, b=0, c=0, and d=0.)
  2. count the number of ID attributes in the selector (= b)
  3. count the number of other attributes and pseudo-classes in the selector (= c)
  4. count the number of element names and pseudo-elements in the selector (= d)

via W3C:Calculating a selector's specificity

翻译成中文如下:

  1. 如果规则是写在标签的style属性中(内联样式),则 A=1,否则 A=0。对于内联样式,由于没有选择器,所以 B、C、D 的值都为 0,即 A=1, B=0, C=0, D=0(简写为 1,0,0,0,下同)。
  2. 计算该选择器中ID的数量。(例如,#header 这样的选择器,计算为 0, 1, 0, 0)。
  3. 计算该选择器中伪类及其它属性的数量(包括类选择器、属性选择器等,不包括伪元素选择器)。 (例如.logo[id='site-logo'] 这样的选择器,计算为 0, 0, 2, 0)。
  4. 计算该选择器中伪元素及标签的数量。(例如,p:first-letter 这样的选择器,计算为0, 0, 0, 2)。

W3C 还给出了更为详细的实例解析:

 *             {}  /* a=0 b=0 c=0 d=0 -> specificity = 0, 0, 0, 0 */
 li            {}  /* a=0 b=0 c=0 d=1 -> specificity = 0, 0, 0, 1 */
 li:first-line {}  /* a=0 b=0 c=0 d=2 -> specificity = 0, 0, 0, 2 */
 ul li         {}  /* a=0 b=0 c=0 d=2 -> specificity = 0, 0, 0, 2 */
 ul ol+li      {}  /* a=0 b=0 c=0 d=3 -> specificity = 0, 0, 0, 3 */
 h1 + *[rel=up]{}  /* a=0 b=0 c=1 d=1 -> specificity = 0, 0, 1, 1 */
 ul ol li.red  {}  /* a=0 b=0 c=1 d=3 -> specificity = 0, 0, 1, 3 */
 li.red.level  {}  /* a=0 b=0 c=2 d=1 -> specificity = 0, 0, 2, 1 */
 #x34y         {}  /* a=0 b=1 c=0 d=0 -> specificity = 0, 1, 0, 0 */
 style=""          /* a=1 b=0 c=0 d=0 -> specificity = 1, 0, 0, 0 */

所以很多人将上述规则总结成下表:

选择器 表达式或者示例 权重 说明 specificity
内联样式 style="" 1000 inline style [1,0,0,0]
ID选择器 #IdSelector 100 id selectors [0,1,0,0]
类选择器 .class-selector 10 class selectors
属性选择器 [title=""] 10 attributes selectors
伪类选择器 :first-child 10 pseudo-classes selectors
伪元素选择器 p:first-letter 1 pseudo-elements selectors
标签选择器 div 1 type selectors

从单个样式选择器来看 CSS 权重优先级,我们可总结出如下公式:

!important > 内嵌样式 > ID选择器(#id > class选择器(.class > 标签选择器、伪类选择器、属性选择器 > 伪元素 > 通配符选择器(* >继承(inherit

CSS 规则包含多个选择器情况,以下的选择器应拆分为两个选择器再计算

选择器 表达式或者示例 说明
相邻选择器 selecter + selecter
兄长选择器 selecter ~ selecter
亲子选择器 selecter > selecter
后代选择器 selecter selecter

如果数值还是很抽象的话,那么下图更加直观的展示了 CSS 权重是如何计算的:

这样量化权重值之后,很直观,但是权重值不是 10 进制的也不会进位,不要以为 11 个 class 选择器就能抵得过一个 id 选择器。我们可以用以下代码作为测试:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>11 class selector Vs 1 id selector</title>
    <style type="text/css">
        /* 一个id 选择器 */
        #testId {
            color: yellow;
        }
        /* 11个class 选择器 */
        .test .test .test .test .test .test .test .test .test .test .test {
            color : red;
        }
    </style>
</head>
<body>
    <div class="test">
        <div class="test">
            <div class="test">
                <div class="test">
                    <div class="test">
                        <div class="test">
                            <div class="test">
                                <div class="test">
                                    <div class="test">
                                        <div class="test">
                                          <div class="test" id="testId">
                                            看我颜色
                                            </div><!-- 11个嵌套的 div -->
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</body>
</html>

结果也验证了,上述猜想是错误的,最终结果文字颜色是红色的。

在某些浏览器中 256 个类选择器的却能干的过一个ID选择器,但是这只是一个Bug。

!important

!important

inherit

not

参考资料&文档:

  1. W3.org Specificity
  2. 深入解析CSS样式层叠权重值
  3. CSS选择器的权重详解

发表评论

电子邮件地址不会被公开。 必填项已用*标注