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

什么是选择器?

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

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

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

听到最多的例子如下:

a-b-c

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

!important > inline style > ID > class > tag

那么对于这样的一个例子

    

    

SPAN

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

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

关于CSS选择器的权重计算方法纠正_第1张图片

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




    
    
    
    Document
    



    

先定义好css

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

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

可是......

关于CSS选择器的权重计算方法纠正_第2张图片
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~

你可能感兴趣的:(关于CSS选择器的权重计算方法纠正)