深入理解CSS选择器优先级的计算

来源:网络整理  作者:博客园  浏览:
相关专题: CSS3教程
导读: 选择器的优先级关系到元素应用哪个样式。在CSS2.1的规范中是这样描述的: 1.如果声明来自于“style”属性,而不是带有选择器的规则,则记为 1,否则记为 0 (= a)(HTML元素的style属 ...
选择器的优先级关系到元素应用哪个样式。在CSS2.1的规范中是这样描述的:
1.如果声明来自于“style”属性,而不是带有选择器的规则,则记为 1,否则记为 0 (= a)(HTML元素的style属性也是样式规则,因为这些样式规则没有选择器,因此记为a=1,b=0,c=0,d=0)
2.计算选择器中 ID 属性的个数 (= b)
3.计算选择器中其他属性(类、属性选择器)和伪类的个数 (= c)
4.计算选择器中元素名称和伪元素的个数 (= d)


将四个数字按 a-b-c-d 这样连接起来(位于大数进制的数字系统中),构成选择器的优先级。


在最新的Selector Level 3规范中:

1.计算选择器中 ID 属性的个数 (= a)
2.计算选择器中其他属性(类、属性选择器)和伪类的个数 (= b)
3.计算选择器中元素名称和伪元素的个数 (= c)
4.忽略通用选择器*


将三个数字按 a-b-c这样连接起来(位于大数进制的数字系统中),构成选择器的优先级。style属性计算参考css2.1规范。



问题:


1、选择器的整体优先级如何计算,是像网上说的a*1000+b*100+c*10+d吗?


       答:不是。这种回答明显是望文生义。四级(a、b、c、d)之间并不是简单的相加关系。同一级(例如:a对a)的才具有可比关系。


分析:


以下为webkit的webCore中关于优先级计算的代码


  1. unsigned CSSSelector::specificity() const
  2. {
  3.     // make sure the result doesn't overflow
  4.     static const unsigned maxValueMask = 0xffffff; // 整个选择器的最大值,十进制表示:idMask + classMask + elementMak = 16777215
  5.     static const unsigned idMask = 0xff0000; // ID选择器的最大值,十进制表示:(16*16+16)*16^4=16711680
  6.     static const unsigned classMask = 0xff00; // class(伪类、类)选择器的最大值,十进制表示:(16*16+16)*16^2=65280
  7.     static const unsigned elementMask = 0xff; // 元素选择器的最大值,十进制表示:16*16+16=255

  8.     if (isForPage())
  9.         return specificityForPage() & maxValueMask;

  10.     unsigned total = 0;
  11.     unsigned temp = 0;

  12.     for (const CSSSelector* selector = this; selector; selector = selector->tagHistory()) {
  13.         temp = total + selector->specificityForOneSelector();
  14.         // Clamp each component to its max in the case of overflow.
  15.         if ((temp & idMask) < (total & idMask)) // 判断是否为ID选择器
  16.             total |= idMask; // 保证ID选择器的同类叠加不会超过ID选择器的总最大值,下同
  17.         else if ((temp & classMask) < (total & classMask))
  18.             total |= classMask;
  19.         else if ((temp & elementMask) < (total & elementMask))
  20.             total |= elementMask;
  21.         else
  22.             total = temp;
  23.     }
  24.     return total;
  25. }

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

  33.     case PseudoClass:
  34.         // FIXME: PsuedoAny should base the specificity on the sub-selectors.
  35.         // See http://lists.w3.org/Archives/Public/www-style/2010Sep/0530.html
  36.         if (pseudoClassType() == PseudoClassNot && selectorList())
  37.             return selectorList()->first()->specificityForOneSelector();
  38.         FALLTHROUGH;
  39.     case Exact:
  40.     case Class: