css优先级计算规则

    最近面试了一些求职者,我问 css 优先级计算规则是怎样的?答曰 ID 优先级 >class> 元素选择器,外联样式优先级低于内联样式,内联样式优先级低于行间样式,然后就没有然后了……,ID 选择器的优先级确实 >class 选择器的优先级 > 元素选择器的优先级,但是外联样式优先级并不一定低于内联样式优先级。做为一个合格的前端工程师,让我们彻底搞清楚 css 优先级计算规则吧!

    特殊性

    css 继承是从一个元素向其后代元素传递属性值所采用的机制。确定应当向一个元素应用哪些值时,浏览器不仅要考虑继承,还要考虑声明的特殊性,另外需要考虑声明本身的来源。这个过程就称为层叠。——《css 权威指南》

上面这句话有两个词需要稍作解释,“声明”和“特殊性”。如下图,css 规则由选择器和声明块组成,写在选择器后面大括号里的就叫声明。

    实际上,同一个元素可以使用多个规则来指定它的字体颜色,每个规则都有自己的选择器。显然最终只有一个规则起作用(不可能一个字既是红色又是绿色),那么该规则的特殊性最高,特殊性即 css 优先级。很多同学仅仅知道选择器优先级 ID>class> 元素选择器,而不知道 ID 的优先级为什么大于 class 的优先级。那么 css 优先级到底是怎么计算的呢?

    选择器的特殊性值表述为 4 个部分,用 0,0,0,0 表示。

  • ID 选择器的特殊性值,加 0,1,0,0
  • 类选择器、属性选择器或伪类,加 0,0,1,0
  • 元素和伪元素,加 0,0,0,1
  • 通配选择器 * 对特殊性没有贡献,即 0,0,0,0
  • 最后比较特殊的一个标志!important(权重),它没有特殊性值,但它的优先级是最高的,为了方便记忆,可以认为它的特殊性值为 1,0,0,0,0

    例如:以下规则中选择器的特殊性分别是:    

1 a{color: yellow;} /*特殊性值:0,0,0,1*/
2 div a{color: green;} /*特殊性值:0,0,0,2*/
3 .demo a{color: black;} /*特殊性值:0,0,1,1*/
4 .demo input[type="text"]{color: blue;} /*特殊性值:0,0,2,1*/
5 .demo *[type="text"]{color: grey;} /*特殊性值:0,0,2,0*/
6 #demo a{color: orange;} /*特殊性值:0,1,0,1*/
7 div#demo a{color: red;} /*特殊性值:0,1,0,2*/

 对照下面的demo,来验证上面几组规则的正确与否:

<a href="">第一条应该是黄色</a> <!--适用第 1 行规则-->
<div class="demo">
    <input type="text" value="第二条应该是蓝色" /><!--适用第 4、5 行规则,第 4 行优先级高-->
    <a href="">第三条应该是黑色</a><!--适用第 2、3 行规则,第 3 行优先级高-->
</div>
<div id="demo">
    <a href="">第四条应该是红色</a><!--适用第 6、7 行规则,第 7 行优先级高-->
</div>

显示效果:

    分析上面的 demo,要注意特殊性是怎么排序的,上面第 4 行和第 5 行规则,第 4 行之所以优先级比第 5 行高,是因为第四行特殊性值最后面是 1,而第 5 行特殊性值最后面是 0。回过头来回答文章最开始的问题,为什么 ID 选择器的优先级比类选择器的优先级高?实际上是因为选择器特殊性值是从左向右排序的,特殊性值 1,0,0,0 大于以 0 开头的所有特殊性值,即便它是 0,99,99,99,优先级依然比 1,0,0,0 要低。

    前面有讲到通配选择器 * 的特殊性值是 0,0,0,0,而元素通过父元素继承过来的样式是没有特殊性值的,所以,通配选择器定义的规则优先级高于元素继承过来的规则的优先级

    细心的同学应该已经发现了,特殊性值中的 4 个 0 中的第一个 0 是给谁暗箱操作内定了吗?是的!DOM 中的行间样式送了点红包,于是它就牛了。行间样式的特殊性是 1,0,0,0。行间样式的优先级比 ID 选择器优先级高。

 

    层叠

    假如特殊性相同的两条规则应用到同一个元素会怎样?css 会先查看规则的权重(!important),加了权重的优先级最高,当权重相同的时候,会比较规则的特殊性,根据前面的优先级计算规则决定哪条规则起作用,当特殊性值也一样的时候,css 规则会按顺序排序,后声明的规则优先级高,成为人生赢家,当上总经理出任 CEO 迎娶白富美。

    我们知道 a 标签有四种状态:链接访问前、链接访问后、鼠标滑过、激活,分别对应四种伪类:link、:visited、:hover、:active,并且这四个伪类如果对同一个元素设置同一个属性,那它们的声明顺序还有一定要求,一般大家都遵循“爱恨原则 LVHA”(LoVe HAte),为什么是这个顺序?不能是其它顺序吗?

    根据 css 优先级计算规则,伪类的特殊性值是 0,0,1,0,4 个伪类的特殊性值相同,那么后面声明的规则优先级高。当鼠标滑过 a 链接时,满足:link 和:hover 两个伪类,要改变 a 标签的颜色,就必须将:hover 伪类在:link 伪类后面声明;同理,当鼠标点击激活 a 链接时,同时满足:link、:hover、:active 三种状态,要显示 a 标签激活时的样式(:active),必须将:active 声明放到:link 和:hover 之后。因此得出 LVHA 这个顺序。这个顺序能不能变?可以,但也只有:link 和:visited 可以交换位置,因为一个链接要么访问过要么没访问过,不可能同时满足,也就不存在覆盖的问题。

###########2017-5-8 补充 ############

有意思的是,如果某个元素 class(类选择器)的数量大于 255 个,不同的浏览器的表现不一致,包括但不限于以下浏览器认为 class 选择器的优先级会超过 id 选择器:

Firefox 52.0.2 (64 位)

IE 11

 

###########################

本文地址:http://www.cnblogs.com/wangmeijian/p/4207433.html

By 王美建 from 博客园 原创文章,转载请保留署名及出处