css & 深入理解 css 选择器优先级

324 阅读3分钟

1、什么是选择器优先级?

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

上述字段定义来自developer.mozilla.org/zh-CN/docs/…

  • 先抛出个问题,下面例子字体颜色最终是什么颜色,以及为什么?
<div class="item" id="item">
    item
</div>

<style>
#item {
	color: #f00;
}/*红色*/

.item  {
	color: #0f0;
}/*绿色*/
</style>

答案很简单:红色。

这就涉及到了优先级问题,同一块内容,我们同时用了 ID选择器类选择器,因为 ID选择器 优先级大于 类选择器 , 所以最终显示为红色。

2、优先级的计算规则

普遍已知选择器优先级关系是:

内联 > ID选择器 > 类选择器 > 标签选择器

但是,浏览器具体的优先级算法是怎样的?可能还有些人不知道。《CSS Refactoring》中提到了算法的过程 。

A specificity is determined by plugging numbers into A, B, C, D):

  • If the styles are applied via the style attribute, a=1; otherwise, a=0.
  • B is equal to the number of ID selectors present.
  • C is equal to the number of class selectors, attribute selectors, and pseudoclasses present.
  • D is equal to the number of type selectors and pseudoelements present.

翻译过来就是:

优先级是由 ABCD 的值来决定的,其中它们的值计算规则如下:

  1. 如果存在内联样式,那么 A = 1, 否则 A = 0;
  2. B 的值等于 ID选择器(#id) 出现的次数;
  3. C 的值等于 类选择器(.class)属性选择器(a[href="https://www.baidu.com"])伪类(:first-child) 出现的总次数;
  4. D 的值等于 标签选择器(div,span,a)伪元素(::before,::after) 出现的总次数 。

以上理论根据奉上,先上个栗子:

#name > div > span > a.hover

套用上面的算法,依次求出 A B C D 的值:

  1. 因为没有内联样式 ,所以 A = 0
  2. ID选择器总共出现了1次, B = 1
  3. 类选择器出现了1次, 属性选择器出现了0次,伪类选择器出现0次,所以 C = (1 + 0 + 0) = 1
  4. 标签选择器出现了3次, 伪元素出现了0次,所以 D = (3 + 0) = 3

通过以上步骤算出的ABCD 可以简记作:(0, 1, 1, 3)

为了熟悉掌握优先级算法 ,我们再来做一些练习:

li                                  	/* (0, 0, 0, 1) */
ul li                               	/* (0, 0, 0, 2) */
ul ol+li                            	/* (0, 0, 0, 3) */
h1 + *[REL=up]                      	/* (0, 0, 1, 1) */
ul ol li.red                        	/* (0, 0, 1, 3) */
li.red.level                        	/* (0, 0, 2, 1) */
.a1.a2.a3.a4.a5.a6.a7.a8.a9.a10.a11  	/* (0, 0, 11,0) */
#name                              		/* (0, 1, 0, 0) */
li:nth-child(odd) main .name       		/* (0, 0, 2, 2) */
#name .active > a:hover            		/* (0, 1, 2, 1) */
html body #name .active > a:hover  		/* (0, 1, 2, 3) */

通过一段小代码的练习已经能清楚了优先级是怎么算的了。但是,还有一个问题,怎么比较两个优先级的高低呢? 比较规则是: 从左往右依次进行比较 ,较大者胜出,如果相等,则继续往右移动一位进行比较 。如果4位全部相等,则后面的会覆盖前面的

再举一个栗子:

<div class="list" id="list">
    <div class="item">item</div>
</div>

<style>
#list .item {
	color: #f00;
}/*(0, 1, 1, 0)*/

.list .item {
	color: #0f0;
}/*(0, 0, 2, 0)*/
</style>

现在,再通过一个相同的例子大家应该都能理解为什么字体会是红色的了。

3、总结

根据以上现知内联样式的优先级是最高的,如果外部样式想要覆盖内联样式,使用!important 即可。

但是! 一般情况下,很少会使用内联样式 ,所以 !important 也很少会用到!如果不是为了要覆盖内联样式,建议尽量不要使用 !important !!!

最后一个栗子:

<div id="app" style="color:#f00!important">app</div>

<style>
#id {
	color: 0f0 !important;
}
</style>

如以上这种情况当内联中出现 !important时,无论如何书写外联都无法覆盖内联了,所以,这种情况在实际代码中是要杜绝的!记住,千万不要在内联样式中使用 !important!!!