选择器的优先级关系到元素应用哪个样式。在CSS2.1的规范(http://www.w3.org/TR/2009/CR-CSS2-20090908/cascade.html#specificity)中是这样描述的:

  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中关于优先级计算的代码(http://trac.webkit.org/browser/trunk/Source/WebCore/css/CSSSelector.cpp
unsigned CSSSelector::specificity() const
{
// make sure the result doesn't overflow
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 if (isForPage())
return specificityForPage() & maxValueMask; unsigned total = ;
unsigned temp = ; for (const CSSSelector* selector = this; selector; selector = selector->tagHistory()) {
temp = total + selector->specificityForOneSelector();
// Clamp each component to its max in the case of overflow.
if ((temp & idMask) < (total & idMask)) // 判断是否为ID选择器
total |= idMask; // 保证ID选择器的同类叠加不会超过ID选择器的总最大值,下同
else if ((temp & classMask) < (total & classMask))
total |= classMask;
else if ((temp & elementMask) < (total & elementMask))
total |= elementMask;
else
total = temp;
}
return total;
} 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) ? : ; // 元素选择器权重
case Unknown:
return ;
}
ASSERT_NOT_REACHED();
return ;
}
 
      从上面的代码可以看出,在webkit中,对于a级选择器(“style”属性的样式规则),根本不参与优先级运算的过程。对于b级(ID选择器)、c级(class选择器)、d级(元素选择器),每一级都有自己的最大值(最大数目255),超出时就会应用其最大值(最大数目)。b级最大值为0xff0000(16711680),权重为0x1000(65536),数目超过256时仍然使用最大值。c级、d级相似。所以并不存在低一级超出一定数目后导致高一级进一出现覆盖的情况。在一个选择器组(em:#a .d div)中,所有选择器的加和不会超过16777215(每一类的选择器都保证了不会超出最大值的情况)。demo:http://jsbin.com/duker/2。对于!important,webkit是走的另一条路径(具有!important的样式规则大于没有!important的样式规则,只有在同时具有!important属性时才会比较选择器的整体优先级)。整体来说,在webkit中,!important>inline style>ID>class>tag。
      webkit是在http://trac.webkit.org/changeset/130444/trunk/Source/WebCore/css/CSSSelector.cpp这一次的修订中加上对于优先级溢出的处理的(chrome发布版本很快,今年改用了blink,可以认为chrome都遵守了特殊性(优先级)计算的标准):

时间戳:2012-10-04 19:04:44 (20个月前)作者:commit-queue@webkit.org消息:

选择器特殊性类别溢出到高类别
​https://bugs.webkit.org/show_bug.cgi?id=98295

Patch by Tab Atkins <​jackalmage@gmail.com> on 2012-10-04
Reviewed by Eric Seidel.

这一次添加的补丁是为了对于CSS选择器的特殊性添加溢出策略。

以前我们并不会检测每个类别的特殊性溢出问题。原始的策略是:把每个类别存储为一个字节(2^8=256),然后整体存在一个无符号整型数中。这样的话就会导致256个同一类别的单选择器等于1个高类别的选择器。但是这违反了选择器的特殊性规则,导致样式规则排序问题。

Tests: /fast/selectors/specificity-overflow.html

  • css/CSSSelector.cpp:

(WebCore::CSSSelector::specificity):

 
 
      mozilla中关于优先级计算的代码(地址为http://hg.mozilla.org/mozilla-central/file/7297dedf2416/layout/style/StyleRule.cpp(472行-537行)):
int32_t nsCSSSelector::CalcWeightWithoutNegations() const
{
int32_t weight = ; #ifdef MOZ_XUL
MOZ_ASSERT(!(IsPseudoElement() &&
PseudoType() != nsCSSPseudoElements::ePseudo_XULTree &&
mClassList),
"If non-XUL-tree pseudo-elements can have class selectors "
"after them, specificity calculation must be updated");
#else
MOZ_ASSERT(!(IsPseudoElement() && mClassList),
"If pseudo-elements can have class selectors "
"after them, specificity calculation must be updated");
#endif
MOZ_ASSERT(!(IsPseudoElement() && (mIDList || mAttrList)),
"If pseudo-elements can have id or attribute selectors "
"after them, specificity calculation must be updated"); if (nullptr != mCasedTag) {
weight += 0x000001;
}
nsAtomList* list = mIDList;
while (nullptr != list) {
weight += 0x010000;
list = list->mNext;
}
list = mClassList;
#ifdef MOZ_XUL
// XUL tree pseudo-elements abuse mClassList to store some private
// data; ignore that.
if (PseudoType() == nsCSSPseudoElements::ePseudo_XULTree) {
list = nullptr;
}
#endif
while (nullptr != list) {
weight += 0x000100;
list = list->mNext;
}
// FIXME (bug 561154): This is incorrect for :-moz-any(), which isn't
// really a pseudo-class. In order to handle :-moz-any() correctly,
// we need to compute specificity after we match, based on which
// option we matched with (and thus also need to try the
// highest-specificity options first).
nsPseudoClassList *plist = mPseudoClassList;
while (nullptr != plist) {
weight += 0x000100;
plist = plist->mNext;
}
nsAttrSelector* attr = mAttrList;
while (nullptr != attr) {
weight += 0x000100;
attr = attr->mNext;
}
return weight;
} int32_t nsCSSSelector::CalcWeight() const
{
// Loop over this selector and all its negations.
int32_t weight = ;
for (const nsCSSSelector *n = this; n; n = n->mNegations) {
weight += n->CalcWeightWithoutNegations();
}
return weight;
}
      和webkit一样,inline style元素不计入计算。对于b级(ID)、c级(class)、d级(tag)的最大值和最小值也都和webkit保持一致。不同的是在mozilla中并没有对于同一类别的选择器进行最大值控制,而是结果直接相加。这样的话就会导致同一级选择器数目多于255时高一级进一,也就是结果溢出的问题。而且对于整个选择器组的优先级计算因为没有类似于webkit的按位与运算来保证结果不溢出,只是简单的相加,在mozilla中就可能出现溢出的问题。
 
      因为IE无法阅读代码,所以对于IE系列只能采取demo测试的方法来确认问题。在所有IE系列(q、s)中,表现都和mozilla一致。包括最新的IE11。
 
注:CSS选择器还有一个继承性:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<style>
*{font-size:40px;}
#test {font-size:12px !important;}
p {font-size:24px;}
</style>
<body>
<div id="test"><p>test text</p></div>
</body>

在所有浏览器中文字都会应用p {font-size:24px;}。如果把这句去掉的话,就会应用*{font-size:40px;},*包括p。(继承的样式没有优先级)

 
 

结论:

1、优先级计算时跨级相加应注意溢出问题;

2、优先级计算不包括inline style和!important;

3、优先级计算只有同一类别才具有可比性(一般也不会有人定义超出255个的同一选择器)。

 
顺便引用stackoverflow上的一个回答来结束这篇文章:

I am currently using the book CSS Mastery: Advanced Web Standards Solutions.

Chapter 1, page 16 says:

To calculate how specific a rule is, each type of selector is assigned a numeric value. The specificity of a rule is then calculated by adding up the value of each of its selectors. Unfortunately, specificity is not calculated in base 10 but a high, unspecified, base number. This is to ensure that a highly specific selector, such as an ID selector, is never overridden by lots of less specific selectors, such as type selectors.

参考文章:

深入理解CSS选择器优先级的计算的更多相关文章

  1. 看完就懂--CSS选择器优先级的计算

    CSS选择器优先级的计算 什么是选择器的优先级 优先级的计算与比较(一) - 优先级具有可加性 - 选择器优先级不会超过自身最大数量级 - 同等优先级情况下,后写的覆盖前写的 - 并集选择器之间的优先 ...

  2. 深入理解CSS选择器优先级

    题外话 今天把 <CSS REFACTORING>(中文名叫<CSS重构:样式表性能调优>)电子书粗略的浏览了一遍,这本书很薄,150页左右,首先是介绍了什么是重构并举了两个简 ...

  3. css 选择器优先级的计算过程

    以下转自互联网 下面看看官方对选择器的定义:一个选择器的优先级由四个数字a,b,c,d确定.当比较两个选择器时,先比较a,a值大的优先级高,如果a相等则比较b,b值大的优先级高,以此类推.因此,无论b ...

  4. 关于Css选择器优先级

    今天练习css的时候,重叠后的style发现不起作用,原来css选择器优先级大有文章. 声明: yi下内容选自 51cto.com  --加以自己的理解 以备日后参照使用,毕竟自己理解的才是自己的. ...

  5. CSS选择器优先级(转)

    原文:http://www.cnblogs.com/wangfupeng1988/p/4285251.html 另外,w3c有文章介绍了CSS选择器的特定性,见https://www.w3.org/T ...

  6. day44:CSS选择器优先级&JS基础

      目录 1.CSS选择器优先级 2.补充:margin是可以设置百分比的 3.JS 3.1 js代码的引入方式 3.2 变量 3.3 数据类型 3.4 数组(类似于python中的列表) 3.5 自 ...

  7. CSS选择器优先级总结

    CSS三大特性-- 继承. 优先级和层叠. 继承:即子类元素继承父类的样式; 优先级:是指不同类别样式的权重比较; 层叠:是说当数量相同时,通过层叠(后者覆盖前者)的样式. css选择符分类 首先来看 ...

  8. css选择器优先级全解析

    这样一个问题: <!doctype html> <htmllang="en"> <head> <metacharset="UTF ...

  9. CSS选择器优先级 CSS权值

    计算指定选择器的优先级:重新认识CSS的权重 标签的权值为 0,0,0,1 类的权值为 0,0,1,0 属性选择的权值为 0,0,1,1  ID的权值为 0,1,0,0 important的权值为最高 ...

随机推荐

  1. springMVC+ mongdb + redis +Jedis 环境搭建

    环境信息: JDK1.7 : Eclipse 4.4.1 ; mongdb + mongVUE:mongDB的安装 redis的下载和安装:window下安装redis maven3.0.5 新建ma ...

  2. 一个强大的LogParser的UI工具--logparserlizard简介(开源IIS日志分析工具)

    原文地址:http://blog.csdn.net/downmoon/article/details/4509513 日志分析,特别是IIS日志,一般人都会想到LogParser工具,的确很强.但是命 ...

  3. Mac 下 Scala 平台搭建

    1.先要安装 JDK,下载地址: http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html ...

  4. 安卓开发24:FrameLayout布局

    FrameLayout布局 FrameLayout是五大布局中最简单的一个布局.FrameLayout布局中的元素会根据先后顺序重叠起来.利用FrameLayout布局元素重叠的特性,我们一般可以做一 ...

  5. 在sql语句中使用plsql变量

    示例代码如下: create or replace type ua_id_table is table of number; declare v_tab ua_id_table;begin v_tab ...

  6. 跟Google学习Android开发-起始篇-用碎片构建一个动态的用户界面(3)

    4.3 构建一个灵活的用户界面 当设计你的应用程序要支持大范围的屏幕尺寸时,你可以在不同的布局配置中重用碎片,来根据可用的屏幕空间优化用户体验. 例如,在手持设备上,它可能是适应来在一个单窗格用户界面 ...

  7. 使用Fastjson提示No serializer found for class

    在调用Json串生成方法时,提示: No serializer found for class com.jeremxy.domain.EpgDetail and no propertiesdiscov ...

  8. C# 将MSMQ消息转换成Json格式 【优化】

    C# 将MSMQ消息转换成Json格式  [优化] 转换函数: private string ConvertToJSON(string label, string body) { //TODO: co ...

  9. 非对称加密算法RSA--转

    RSA     这种算法1978年就出现了,它是第一个既能用于数据加密也能用于数字签名的算法.它易于理解和操作,也很流行.算法的名字以发明者的名字命名:Ron Rivest, AdiShamir 和L ...

  10. MegaCLI SAS RAID Management Tool

    MegaCLI SAS RAID Management Tool  Ver 8.04.08 July 05, 2012    (c)Copyright 2011, LSI Corporation, A ...