前端面试CSS系列——选择器、权重计算(二)

面试问答

问:CSS选择器权重如何计算?(或者CSS选择器的优先级是如何计算的?)css

答:CSS权重的计算分为四个等级a,b,c,d;其中HTML元素的style属性中定义的声明属于a级,id选择器属于b级,属性选择器、class类选择器和伪类选择器属于c级,类型选择器属于d级;四级当中a级权重值最高,d级权重值最低。权重值根据每一个级别出现的数量进行计数,每一个等级出现1次,就计数1次。权重值的比较按照a,b,c,d 四个等级计算出来的数字从高到低依次比较,若是相同等级下的值PK出结果,就不会进行后面的比较了。若是相同等级的数字相同,则继续比较下级的数字大小。其中有些选择器是不参与优先级的计算,其中包括:通用选择器『*』号,否认伪类:not选择器,组合选择器中的子类选择器、相邻兄弟选择器、普通兄弟选择器。不过否认伪类选择器当中的选择器是会参与选择器优先级计算的。包含!important的CSS声明是特殊的存在,不参与权重值的计算,比a,b,c,d四个等级都高;在同时都包含!important时,又会根据选择器的匹配规则计算权重值。谁的权重值高,应用谁的样式。html

基本概念

CSS规则

CSS规则是由两个主要的部分构成:选择器,以及一条或多条声明;
CSS规则前端

选择器一般是须要改变样式的HTML元素;声明由一个属性和一个值组成。属性是但愿设置的样式属性,每一个属性有一个值(属性值),属性和值被冒号分开。面试

优先级

浏览器经过 优先级来判断哪些属性值与一个元素最为相关,从而在该元素上应用这些属性值。优先级是基于不一样种类选择器组成的匹配规则。

再重审一下,优先级是基于不一样种类选择器组成的匹配规则。咱们还用上面CSS规则当中的图片示例作说明,浏览器

// 选择器『p』就是计算优先级的『匹配规则』
p { font-size:14px; background:#ff0;}

ul#nav li.active a { font-size:14px; }
body.ie7 .col_3 h2~h2 { font-size:16px; }

//『ul#nav li.active a』 和 『body.ie7 .col_3 h2~h2』 是计算优先级的匹配规则

权重

权重是由匹配的选择器中的每一种选择器类型的数值决定的,权重计算获得的数字越大,相对应的匹配规则优先级越高。若是一个CSS声明在两个优先级相等的匹配规则中定义的时候,则按照匹配规则在CSS文件当中的顺序,在最后匹配规则中的CSS声明将会被应用到元素上。post

示例字体

<div id="id" class="class">个人字体大小</div>
#id {
 font-size:18px;
}
.class {
 font-size:16px;
}

最后文字的大小是18px,根据选择器类型的计算结果#id的值是:1,0,0;.class的值是:0,1,0。ui

计算的过程咱们先按下不表,在后面说明spa

点击查看代码示例code

优先级相等的匹配规则

.class{
    font-size:18px;
}
[class='class']{
    font-size:16px;
}
最后文字的大小是16px,根据选择器类型的计算结果,.class的值是:0,1,0,[class='class']的值是:0,1,0。

点击查看代码示例

特异性

上面咱们说#id的计算结果是:1,0,0;.class和[class='class']的计算结果是:0,1,0。为何会计算出这样的值?这就是咱们要说的特异性,英文specificity。下面引用W3C官方的原文:

A selector's specificity is calculated as follows:

  • count 1 if the declaration is from is a 'style' attribute rather than a rule with a selector, 0 otherwise (= a) (In HTML, values of an element's "style" attribute are style sheet rules. These rules have no selectors, so a=1, b=0, c=0, and d=0.)
  • count the number of ID attributes in the selector (= b)
  • count the number of other attributes and pseudo-classes in the selector (= c)
  • count the number of element names and pseudo-elements in the selector (= d)

The specificity is based only on the form of the selector. In particular, a selector of the form "[id=p33]" is counted as an attribute selector (a=0, b=0, c=1, d=0), even if the id attribute is defined as an "ID" in the source document's DTD.

Concatenating the four numbers a-b-c-d (in a number system with a large base) gives the specificity.

选择器的特异性计算规则以下:

  • 若是CSS声明来自HTML元素的style属性,而不是带有选择器的规则,则计数为1,不然为0;(在HTML中,元素的style属性值是样式表规则。这些规则没有选择器;元素style属性定义的样式规则,在特异性计算当中用a表示,因此一般在HTML中,元素的style属性定义的样式表规则的特异性表示为:a=1,b=0,c=0,d=0。)
  • 计算选择器中id属性的数量,用b表示
  • 计算选择器中的其它属性(包括class属性)和伪类的数量,用c表示
  • 计算选择器中元素名称和伪元素的数量,用d表示

『特异性』这个词真的很是很是很差理解,根据语义彻底不明白说的是什么意思,为了更好的理解,我用『权重值』来表示『特异性』。

计算示例

*              {}  /* a=0 b=0 c=0 d=0 -> 权重值 = 0,0,0,0 */
 li            {}  /* a=0 b=0 c=0 d=1 -> 权重值 = 0,0,0,1 */
 li:first-line {}  /* a=0 b=0 c=0 d=2 -> 权重值 = 0,0,0,2 */
 ul li         {}  /* a=0 b=0 c=0 d=2 -> 权重值 = 0,0,0,2 */
 ul ol+li      {}  /* a=0 b=0 c=0 d=3 -> 权重值 = 0,0,0,3 */
 h1 + *[rel=up]{}  /* a=0 b=0 c=1 d=1 -> 权重值 = 0,0,1,1 */
 ul ol li.red  {}  /* a=0 b=0 c=1 d=3 -> 权重值 = 0,0,1,3 */
 li.red.level  {}  /* a=0 b=0 c=2 d=1 -> 权重值 = 0,0,2,1 */
 #x34y         {}  /* a=0 b=1 c=0 d=0 -> 权重值 = 0,1,0,0 */
 style=""          /* a=1 b=0 c=0 d=0 -> 权重值 = 1,0,0,0 */
注意:当ID选择器被当作属性选择器使用的时候,好比 [id='id'],权重值的计算会把它当中C级来计算

权重值计算规则

权重值 = a*num,b*num,c*num,d*num;

权重值的计算网上还有一种比较常见的说法:style属性定义的样式权重值是1000,一个id选择器权重值是100,一个属性和伪类选择器权重表示为10,一个元素名称和伪元素的权重值为1。好比:
权值的计算

按照咱们说的权重值计算规则,其实图片中的total value 的值应该表示为:0,1,1,3。直接用数字113表示只是为了方便记忆,但选择器优先级的比较却不能经过数字来进行比较。好比:两条匹配规则,一个是11个属性选择器,另外一个是1个id选择器,他们权重值进行比较时:

11个属性选择器获得的结果是110,二ID选择器获得的寄过是100。很明显『11个属性选择器』获得的数字值最大,是否是它的优先级最高呢。咱们实验下:

HTML文本

<div id='id' class='c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11'>
    应用谁的样式
</div>

CSS样式

#id {
    background:red;
}

[id='id'][class~='c1'].c1.c2.c3.c4.c5.c6.c7.c8.c9.c10.c11{
 background:yellow;
}

你也能够点击示例亲自试一下

权重值的比较

当两个权值进行比较的时候,是从A到D逐级将等级位上的权重值(如 权值 1,0,0,0 对应--> A,B,C,D)来进行比较的,而不是简单的 1000个数 + 100个数 + 10个数 + 1个数 的总和来进行比较的,换句话说,低等级的选择器,个数再多也不会越等级超太高等级的选择器的优先级的;请看下图:
权重值的比较
总结

  1. 权重值的比较按照a,b,c,d的等级逐级比较,若是同等级的值相同,继续向下级比较
  2. 若是计算获得的权重值相同,那么哪条匹配规则在最后,就应用谁的CSS声明
  3. !important 是超越上述权重值计算规则以外的,优先级最高。

不参与计算的选择器

并非全部的选择器都参与权重值的计算规则,有些是不参与的,其中包括:

  1. 通用选择器『*』
  2. 否认伪类选择器『:not』
  3. 组合选择器『+,~,>』
否认伪类选择器: :not(), 虽然它自己是不计权重的, 可是写在它里面的 css selector 是须要计算权重的.

!important

!important是特殊的存在,!important 是不在 css 选择器的权重计算范围内的, 而它之因此能让 css 选择器生效是由于浏览器在碰见 !important 时会进行特殊的判断。当多个 !important 须要进行比较时, 会先计算其权重再进行比较。一般来讲, 不提倡使用 !important。不过当咱们须要覆盖style属性中定义的样式时,能够选择使用!important

其它说明

  • 优先级计算无视DOM树中的距离;好比:html pbody p的权重值同样,谁写在后面应用谁的CSS声明
  • 伪类选择器,属性选择器,class选择器的权重值同样

参考

计算选择器的特异性CSS2

分配属性值、级联、继承CSS22

计算选择器的特异性

前端杂谈:css权重

优先级

CSS层叠

CSS继承

深刻理解CSS选择器优先级