选择器的优先级关系到元素应用哪个样式。在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. Android 各版本信息 (维基百科)

    The following tables show the release dates and key features of all Android operating system updates ...

  2. Nodejs in Visual Studio Code 01.简单介绍Nodejs

    1.开始 作者自己:开发人员,Asp.Net , html / js , restful , memcached , oracle ,windows , iis 目标读者:供自己以后回顾 2.我看No ...

  3. 寻找INTERIGHT衬衫男神! [复制链接]

    寻找INTERIGHT衬衫男神! - 公告板 - 京东内部论坛 - Powered by Discuz! 寻找INTERIGHT衬衫男神!   [复制链接]

  4. java集合简介

    java集合主要包括以下几点 Java 集合概述 Collection 接口 Iterator 接口 Set List Map Collections 工具类 Enumeration 1.java集合 ...

  5. 使用FTPClient进行文件服务器内文件的上传和下载

    我用的FTPClient是由Apache组织的commons-net.jar包中的API,这个包用起来非常的方便,很容易上手.我在项目开发的过程中主要用到了文件的上传和下载功能,下面将我开发的代码贴出 ...

  6. Oracle——PL/SQL 语句

    目录: 1.什么是PL/SQL  2.PL/SQL 语法基础 3.PL/SQL 实例 一.过程 实例   二.函数 实例   三.游标的使用 实例 四.动态sql 实例 五.触发器 实例  1.什么是 ...

  7. Android ScrollView

    ScrollView 滚动视图 滚动视图用于为其它组件添加滚动条,在默认的情况下,当窗体中内容比较多,而一屏显示不下时,超出的部分不能被用户所看到.因为Android的布局管理器本身没有提供滚动屏幕的 ...

  8. 索引时利用K-邻近算法过滤重复歌曲

    最近一直在做公司搜索的优化与维护,做完索引和搜索的分离之后,又有一个新需求,因为做的是歌曲方面的搜索,所以在数据库中有多个同歌名,同演唱者的的数据,这样在用户搜索的时候,会出来一大堆不同版本的歌曲,影 ...

  9. [Falcor] Retrieving Multiple Values

    In addition to being able to retrieve a path from a Falcor Model, you can also retrieve multiple Pat ...

  10. Android NumberPicker默认外观的修改

    NumberPicker是Android3.0之后引入的一个控件,在以后的TimePicker和DatePicker时间控件里边都有引用,NumberPicker本身并没有提供接口给开发者修改其默认外 ...