CSS的样式可以以多种方式指定,在最终渲染的时候,浏览器依照什么顺序应用样式一直是一个非常令人头疼的问题。本文尝试以最简单的例子来解释CSS的优先级。

CSS定义的位置

一般来说,有以下几个位置定义元素CSS的样式:

  1. 浏览器默认:未指定样式时,浏览器为元素CSS样式设置的默认值。
  2. 外部样式表:使用<link>标签导入的外部css文件。例如:
    内部样式表
    1
    2
    <link rel="stylesheet" href="example.css" type="text/css">
  3. 内部样式表:指在head部分通过<style>标签定义的样式。例如:
    内部样式表
    1
    2
    3
    4
    5
    <style type="text/css">
    body {background-color: red}
    p {margin-left: 20px}
    </style>
  4. 内联样式:指定义在标签的style属性里的样式。例如:
    内联样式
    1
    2
    3
    4
    <p style="color: red; margin-left: 20px">
    This is a paragraph
    </p>

其中4拥有最高的优先级,2和3拥有相同的优先级,1的优先级最低。相同优先级的样式应用最后出现的样式定义。实质上,所有定义的样式,最后都会被级联(cascade)到页面中,那么,这时候样式的优先级如何决定呢?

CSS的优先级

最新的CSS2.2的Spec对优先级有如下定义:

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的优先级就是一系列的计数运算。这个最终的优先级有4位:abcd。

  • 如果是在元素的style属性里定义的样式,则a取1,否则取0
  • b的取值为样式定义里有多少id选择器(如:#example
  • c的取值为样式定义有多少属性选择器(如[pro=example])、类选择器(如:.example)或者伪类选择器(如::link
  • d的取值为样式里有多少元素名(如:div)或者伪元素(如::first-line

最后优先级取值由上述abcd的值决定。在应用样式时,会依次比较样式的a、b、c、d的值,并应用值较大的。有一点必须要注意的是,id选择器必须使用id选择器样式,也就是#example才能算做b类,如果使用诸如[id=example]的属性选择器的方式,只能算做c类。

具体实例

p元素有id、class和data属性。三个css样式的优先级计算如下表:

编号 css abcd
1 p { color: red; } 0001
2 p.example-class { color: green; } 0010
3 p[data=example-data] { color: blue; } 0010

可见2和3拥有相同的优先级,但是3在2之后定义,因此3会被应用,该段落是蓝色的。

p元素内嵌了一个span元素。三个css样式的优先级计算如下表:

编号 css abcd
1 #pid #sid { color: red; } 0200
2 #pid span { color: green; } 0101
3 span.sclass#sid { color: blue; } 0111

优先级顺序为1>2>3因此,example最后是红色的。

关于!important

在样式定义的分号之前加入!important会使强制覆盖掉之前的样式。如果!important被用在了同一元素的同一样式定义,那么会应用最后!important所定义的样式。

尽管2号样式使用了多个id选择器、类选择器和标签选择器,并且span标签也有自己的内联样式,但是1号样式使用了!important,强制覆盖了其余样式。因此,example的颜色是红色的。

总结

CSS的优先级计算其实就是一系列简单的计数操作。相信在掌握了基本的原理之后,在写前端样式时会节省大量的时间,更加得心应手。