×

CSS-in-Action:样式优先级

96
Bing573
2016.03.24 21:32* 字数 1400

虽然写了不少 CSS代码,有时还是会对一些莫名其妙的样式呈现感到意外,如果你也碰到过这样的情况,这篇总结�也许能帮你解答部分疑问。

我们都知道 CSS 中声明的样式是通过选择器与 DOM 元素匹配的,一个 DOM 元素可以对应一个或多个样式,有时候,如果对应的多个样式存在冲突,浏览器就必须采用一些规则来解决冲突。用 CSS (Cascading Style Sheets,层叠样式表)自己的话来说,这些�规则被统称为“层叠”(cascade)。

层叠由四个概念组成:

  1. 特殊性
  2. 重要性
  3. 来源
  4. 顺序

有了他们四个,天下就没有解决不了的冲突。

特殊性

特殊性是解决多样式冲突的一个重要概念,在 css 中,所有的样式声明都有自己的选择器,而不同的选择器具有不同的特殊性(Specificity)。

我们可以认为特殊性是计算样式重要性的一个权重参数,根据选择器的不同,一共有5种权重:

  1. 内联样式:1000
  2. ID 选择器:100
  3. 类选择器(包括属性选择和伪类):10
  4. 元素和伪元素选择器:1
  5. 结合符和通配符:0

举几个例子

h1 { color: red;} /* 权重 = 1 (元素) */
div h1{color:yellow;} /* 权重 = 2 (元素+元素) */
.emphasized{color: purple;} /* 权重 = 10 (类) */
*.emphasized{color:blue;} /* 权重 = 10 (通配符+类) */
#title{color:orange;}  /* 权重 = 100 (ID) */
div#sidebar a{color:blue;} /* 权重 = 102 (元素+ID+元素)*/

一旦一个选择器的特殊性值被确定,该特殊性值为应用到该选择器所包含的所有样式声明上。

比如

h1{color:red;font-size:32px;}
/**
* 规则 color:red 和规则 font-size:32px 都具备相同的特殊性
* 也就是元素选择器的特殊性 1
*/

用户代理会自动完成对样式声明的分解动作,上面的代码将被用户代理处理为

h1{color:red;}
h1{font-size:32px;}

当某一 DOM元素的样式出现冲突时,浏览器会对比每一条声明的特殊性并采用权重最高者。

关于特殊性,有一点是需要注:0特殊性比无特殊性权重要高,可能这句话理解起来有点抽象。

举个例子

* { color: red;}
h1 {color:black;}
<h1>你猜我是什么<em>颜色</em></h1>

如果没有* {color:red;} 这段声明,整句话都是黑色,因为 em 元素会从其父元素h1中继承样式。但实际情况是通配符样式具有0特殊性,相比完全没有特殊性的继承样式,优先级更高,所以 em 中的颜色二字会采用具有0特殊性的样式 * {color:red;} ,� 从而显示为红色。

重要性

我们可以在样式声明结束分号前插入!important来标志出重要声明,事实上,!important不具备任何特殊性,浏览器会将标志为重要的声明分组放到一起。相比普通组,重要组中的声明总是会胜出。

body h1{ color:red; } /* 特殊性权重  = 2 */
h1{color:orange!important;} /* 特殊性权重 = 1 */
/**
* 但由于第二条规则有!important标志,所以尽管特殊性只有1,仍然胜出
*/

当然了,如果重要组中的声明发生了冲突,还是采用计算特殊性的方式来解决。

h1#title { color:red!important; } /* 特殊性权重  = 101 */
h1.title{color:orange!important;} /* 特殊性权重 = 10 */
/**
* 二条规则都有!important标志,都在重要组中,这时通过比较特殊性决定谁胜出,
* 该例中,第一条规则胜出
*/

来源

在考虑声明重要性的同时,还需要考虑其来源。有的浏览器或者浏览器插件允许用户自己定义样式(称之为读者声明),由此就存在开发者创建的声明与用户自定义声明之间孰轻孰重的问题。

总结一下,根据来源的不同,优先级从高到低依次是:

  1. 读者的重要声明
  2. 开发者的重要声明
  3. 开发者的正常声明
  4. 读者的正常声明
  5. 用户代理声明

用户代理声明也就是浏览器的默认样式,但由于其优先级最低,开发者通常不需要考虑。

顺序

在讨论最后一个影响样式优先级的因素前,我们先总结一下。浏览器在解析样式声明时,首先根据来源和重要性将所有的声明分组排序:

读者的重要声明 -> 开发者的重要声明 -> 开发者的正常声明 -> 读者的正常声明 -> 用户代理声明

然后在各组中分别计算样式声明的特殊性,并按�其权重排序。

这时候,可能大部分冲突都已经解决了,但总有一些顽固分子,他们来源相同、同等重要、特殊性也一样。遇到这样的顽固派,最后的杀手锏就是声明顺序——越后声明的优先级越高。

当然,也有例外的情况,当外部样式声明在内部样式之后,外部样式�会覆盖内部样式中重复的规则。比如下面的代码,页面中的链接样式被外部样式所覆盖,显示为红色而不是蓝色。

h1{color:blue;}
h1{color:red;}

也就是说,上面两条声明,第二条会胜出。

值得一提的是,如果样式表中存在导入的样式,一般认为出现在导入样式表中的声明在前,主样式表中的样式在后。

/* additional.css */
h1{color:blue;}
h1{color:red;}
@import additional.css;

即便 additional.css在主样式表中的h1声明后才被引入,页面中的h1 仍然显示红色。

总结

层叠是层叠样式表中一个非常重要的概念,是冲突声明的排序依据,根据声明的特殊性、重要性、来源和顺序,可以最终确定文档的呈现样式。

公众号搜索:front_end_talk
前端技术
Web note ad 1