量化CSS选择器优先级

CSS优先级是一件很让人头痛的事儿,本文介绍了一种方式来帮助解决这个疑难杂症。如何使用数学方法来量化 CSS 优先级,并设计一种合理的比较方法。

不同类型选择器的优先级

有三种不同的方法来选择要设置的样式。其优先级由高到低依次为:

  1. 通过单独的 ID 或属性选择器进行引用
  2. 通过类名在组合中进行引用
  3. 通过元素标记进行引用

根据受规则影响的元素数量和类型来处理选择器,这与之前处理冲突的两种方法有些不同。这是由于规则不必每次都只应用到一种选择器上,而可以应用到多个不同的选择器上。

因此需要有一个方法来确定可以拥有任意选择器组合规则的优先级,通过将作用范围从宽到窄进行整理来完成规则特性的计算。

量化CSS规则的优先级

一个规则的特性由基于上述编号列表中选择器类型所创建的三部分编号来评价。我们可以创建一个数字组合来计算优先级,这个数字组合以类似 [0, 0, 0] 的形式开始。当处理一个规则时,每个指向 ID 的选择器都会将第一个数字增加 1,所以数字组合会变为 [1, 0, 0]。

下面是个示例,这个规则的选择器中共有 3个 ID 选择器,所以数字组合变为 [3, 0, 0]

1
2
3
4
#heading, #main, #menu, .text, .quote, .boxout, .news, .comments, p, blockquote, {
font-family: Consolas;
font-size: 16px;
}

接着,选择器中的类选择器的数量决定了数字组合中的第二位数字。在上例中,共有 5个类选择器,所以规则优先级现在是 [3, 5, 0].

最后,计算出所有指向元素标记的选择器数量,这个数字被放在数字组合的最后。在上例中有两部分(pblockquote),所以最终的数字组合是 [3, 5, 2],这就是与其他选择器比较优先级时所需要的全部。

在每种类型选择器的数量不超过 9个的情况下,可以将数字组合直接写为一个十进制的数字,比如上例中经过量化之后的优先级为 352。其他经过同样规则量化之后的 CSS 规则,若数值比这个数字小,优先级就比它低;数值比它大的,优先级就高于它。当两条规则拥有相同的数值时,采取”就近原则“,即最近被应用的优先。

使用不同的计数基数

当数字组合类型中的数字数量超过 9时,就要使用更高的基数。例如,量化后的优先级为 [11, 7, 9] 不能直接通过拼接三部分的数字来转换成十进制数字,而是把其转变为更高基数,比如讲 20作为基数(如果有的类型超过 19,就要更大)。

具体做法是分别乘以三个部分并把结果相加,从最右边的数字开始向左进行:

1
2
3
4
20 x 19 = 380;
20 x 20 x 7 = 2800;
20 x 20 x 20 x 11 = 88000;
总和 911800

如果要使用更高的基数,可用当前基数替换左侧的 20。之后,一旦所有规则集合的组合数字都由这种基数转换为十进制形式时,那么确定每个样式的特性和优先级就很简单了。

幸运的是 CSS 预处理器完成了所有这一切,不过了解它的运作过程会对合理构建规则和理解它们的优先级是有益的。

注意: 如果所有优先级的量化计算让人感觉复杂的话,请使用简单的经验规则;通常,修改的元素越少,规则的特性越强,优先级越高。

有些规则比其他规则更合适

当两个或更多规则在优先级上完全相同时,通常是应用最近运行的规则。然而,可以使用 !important 声明来强制一个规则拥有更高的优先级,如:

1
p { color: #ff0000 !important; }

当这样做时,所有之前等价的设定都会被覆盖(也包括使用了 !important 的),所有之后处理的等价规则将会被忽略。例如,下面两条规则中的第二条通常会有优先级,但由于先前的语句使用了 !important,第二条语句会被忽略。

1
2
p { color: #f00 !important; }
p { color: #ff0; }

注意:可以通过创建用户样式表来指定浏览器的默认样式,还可以使用 !important 声明,以便使用户的样式设置优先于当前网页指定的相同属性。不过,那些使用 CSS1 的旧浏览器并不支持这一特性。


参考

  • 《Learing PHP, MySQL, JavaScript, and CSS》(Robin Nixon著,侯荣涛译,中国电力出版社)