关于CSS选择器的权重计算方法纠正

什么是选择器?

选择器表示结构。该结构可以用作条件(例如,在CSS规则中),其确定选择器在文档树中匹配哪些元素,或者作为对应于该结构的HTML或XML片段的平面描述。

计算选择器的特异性(特殊性)

提到css权重计算,初学者可能知道按照选择器分类,赋予权重值和权重系数等等。但是最终计算时,不深入了解就会想当然的觉得权重相乘相加,最终谁最大听谁的,这是不对的。

听到最多的例子如下:

a-b-c

  • ID: 1000(a
  • Class,属性选择器:100(b
  • Element,伪类选择器:10(c

!important > inline style > ID > class > tag

那么对于这样的一个例子

    <style>
        /*a*/
        #id .p span {
            color: red;
        }
        /*b*/
        #id span {
            color: blue;
        }
    </style>

    <div id="id">
        <p class="p">
            <span>SPAN</span>
        </p>
    </div>

a选择器的总权重值为:(1000 * 1) + (100 * 1) + (10 * 1) = 1110
b选择器的总权重值为:(1000 * 1) + (100 * 1) + (10 * 0) = 1100

那么将会使用a选择器的样式应用到DOM树中,最终被渲染出来。

exactly,但是如果真是这样计算权重,只使用b类型选择器,通过改变数量,那么一样可以使得总权重大于a选择器啊。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        #demo span span span span span span span span span span span span span span span span span span span span span span
        span span span span span span span span span span span span span span span span span span span span span span span span
        span span span span span span span span span span span span span span span span span span span span span span span span
        span span span span span span span span span span span span span span span span span span span span span span span span
        span span span span span span span span span span span span span span span span span span span span span span span span
        span span span span span span span span span span span span span span span span span span span span span span span span
        span span span span span span span span span span span span span span span span span span span span span span span span
        span span span span span span span span span span span span span span span span span span span span span span span span
        span span span span span span span span span span span span span span span span span span span span span span span span
        span span span span span span {
        display: block;
        height: 200px;
        height: 100px;
        background-color: red;
        }
        
        #demo .test {display: block; height:200px;height: 100px; background-color: black;}

    </style>
</head>

<body>
    <div id="demo"></div>

    <script>
        var a = document.getElementById("demo")
        b = {};
        for (var i = 0; i < 220; i++) {
            b = document.createElement("span");
            if (i == 219) b.className = "test";
            a.appendChild(b);
            a = b;
        }
    </script>

</body>
</html>

先定义好css

  • 一种就是上例中a构造类型的选择器,由idclass构成
  • 另一种则是大量element名和id构成的选择器

而JS部分,暴力span生span,最终会嵌套220个span,这样一来,1000 + (220 * 10)选择器怎么也比1000 + 100的权重大了吧?最终应该呈现红色背景色才对。

可是......

QQ截图20181217030359.jpg

啪啪啪!脸疼不?

说好的1000 + (220*10)> 1000 + 100呢?

为什么会这样?因为根本就不是那样计算的,或者说,权重值不对。

如何正确计算权重值

W3C文档:Calculating a selector’s specificity

关于数量

选择器的特异性是针对给定元素计算的,如下所示:

  • 计算选择器中ID选择器的数量(= A)
  • 计算选择器中的类选择器,属性选择器和伪类的数量 (= B)
  • 计算选择器中类型选择器和伪元素的数量(= C)
  • 忽略通用选择器

注意,比较的是数量。
例子:#id .p span {}这样的选择器,a-b-c为1-1-1。

通过比较三个组分来比较特异性:具有较大A值的特异性更具体; 如果两个A值相关,则具有较大B值的特异性更具体; 如果两个B值也相关联,则具有较大C值的特异性更具体; 如果所有值都绑定,则两个特征相等。

用boolean表示就是a || b || c

文档也给出一个示例:

Examples:
*               /* a=0 b=0 c=0 */
LI              /* a=0 b=0 c=1 */
UL LI           /* a=0 b=0 c=2 */
UL OL+LI        /* a=0 b=0 c=3 */
H1 + *[REL=up]  /* a=0 b=1 c=1 */
UL OL LI.red    /* a=0 b=1 c=3 */
LI.red.level    /* a=0 b=2 c=1 */
#x34y           /* a=1 b=0 c=0 */
#s12:not(FOO)   /* a=1 b=0 c=1 */
.foo :is(.bar, #baz)
                /* a=1 b=1 c=0 */

但是仅靠数量还不行。


关于权重(重点)

深入理解CSS选择器优先级的计算这篇文章中,作者找到了webkit中的详细解析代码。

其中一段:

    static const unsigned maxValueMask = 0xffffff; // 整个选择器的最大值,十进制表示:idMask + classMask + elementMak = 16777215
    static const unsigned idMask = 0xff0000; // ID选择器的最大值,十进制表示:(16*16+16)*16^4=16711680
    static const unsigned classMask = 0xff00; // class(伪类、类)选择器的最大值,十进制表示:(16*16+16)*16^2=65280
    static const unsigned elementMask = 0xff; // 元素选择器的最大值,十进制表示:16*16+16=255

// ....................

inline unsigned CSSSelector::specificityForOneSelector() const
{
    // FIXME: Pseudo-elements and pseudo-classes do not have the same specificity. This function
    // isn't quite correct.
    switch (m_match) {
    case Id:
        return 0x10000; // ID选择器权重

    case PseudoClass:
        // FIXME: PsuedoAny should base the specificity on the sub-selectors.
        // See http://lists.w3.org/Archives/Public/www-style/2010Sep/0530.html
        if (pseudoClassType() == PseudoClassNot && selectorList())
            return selectorList()->first()->specificityForOneSelector();
        FALLTHROUGH;
    case Exact:
    case Class:
    case Set:
    case List:
    case Hyphen:
    case PseudoElement:
    case Contain:
    case Begin:
    case End:
        return 0x100; // class选择器权重

    case Tag:
        return (tagQName().localName() != starAtom) ? 1 : 0; // 元素选择器权重
    case Unknown:
        return 0;
    }
    ASSERT_NOT_REACHED();
    return 0;
}
  • 对于b级(ID选择器)、c级(class选择器)、d级(元素选择器),每一级都有自己的最大值(最大数目255)超出时就会应用其最大值(最大数目)
  • b级最大值为0xff0000(16711680),权重为0x1000(65536),数目超过256时仍然使用最大值。
  • c级、d级相似。所以并不存在低一级超出一定数目后导致高一级进一出现覆盖的情况。

一个选择器如果只有100个Id,那么b级权重就是:100 * 65536 = 6553600
如果有255个,255 * 65536 = 16711680超过255个仍然使用最高权重16711680表示。

c级权重(Cmax < Bmax)最大值远低于b级,这就避免了低位数量多进位覆盖高位权重情况

over~

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 专业考题类型管理运行工作负责人一般作业考题内容选项A选项B选项C选项D选项E选项F正确答案 变电单选GYSZ本规程...
    小白兔去钓鱼阅读 9,090评论 0 13
  • 选择题部分 1.(),只有在发生短路事故时或者在负荷电流较大时,变流器中才会有足够的二次电流作为继电保护跳闸之用。...
    skystarwuwei阅读 13,667评论 0 7
  • 数据结构与算法 1.算法的有穷性是指( )。答案:A A)算法程序的运行时间是有限的 B)算法程序所处理的数据量是...
    织梦学生阅读 3,525评论 1 15
  • 关于Mongodb的全面总结 MongoDB的内部构造《MongoDB The Definitive Guide》...
    中v中阅读 32,098评论 2 89
  • 问题描述 编程语言书籍中经常解释值类型被创建在栈上,引用类型被创建在堆上,但是并没有本质上解释这堆和栈是什么。我仅...
    波波维奇popovich阅读 307评论 1 3