CSS选择器权重及样式优先级

CSS样式应用到元素上的规则可以简述为:先将所有样式按来源、权重排序;然后取权重高的样式,权重相同的样式根据“就近原则”应用。
我们先从选择器权重说起:

CSS选择器权重

从高到低可以将CSS选择器权重排列如下:

1. 内联样式inline-style权重最高,权值可以记为1000

2. ID选择器,权值记为100

3. Class选择器、属性选择器、伪类选择器,权值记为10

4. 元素、伪元素选择器,权值记为1

5. 通配符选择器*,权值为0(为什么记为0而不是无权重见下方),结合符(空格、+,>)不计入权重

1
2
3
4
h1 {color: red;} /*权重=0001*/
p.siderbar > em {color: purple;} /*权重=0012*/
.clearfloat:after {content:"";display:block;clear:both;} /*权重=0020*/
li#answer {color:navy;} /*权重=0101*/

注意事项

1. 使用属性选择器选择ID,其权重仍为10,如:

1
2
ul > li[id="answer"] {color:navy;} /*权重=0012*/
li#answer {color:navy;} /*权重=0101*/

2. 权重值不会进位,即使有10个元素选择器,其权重也不如一个Class选择器权重高,即000(10)<0010

3. 拥有!important声明的样式声明其权重单独计算

如果一个重要声明(有!important)权重和非重要声明(无!important)冲突,重要声明优先,如:

1
2
h1 {color:red !important;}
#title {color:yellow !important;}
1
<h1 id="title" style="color:black">Final Color is YELLOW</h1>

两个重要声明,第二个#title权重更高,且都优先于内联非重要声明的样式。

4. (默认)继承的样式没有权重,会被通配符样式(0权重)覆盖,如:

1
2
* {color:yellow;}
h1 {color:red;}
1
<h1>RED and <em>YELLOW</em></h1>

em元素继承了h1的color样式,但是因为其无权重,所以会被* {color:yellow;}覆盖。
所以通配符选择器往往有一种短路继承的效果。

但是如果在样式中明确指定使用继承属性值,就要看选择器的权重来决定了。比如在上述CSS中加入em{color:inherit;}
em标签文本就显示为继承下来的红色。

CSS样式应用优先级分析

了解了选择器权重之后,我们就可以来看一下CSS到底是怎么选择某个元素样式的:

  1. 列出每一条样式规则,每条规则都含有一个匹配给定元素的选择器

  2. 按照来源和重要声明对所有样式排序

    CSS的来源有三种:

    • User Agent Stylesheet 用户代理的默认CSS(浏览器默认的CSS)

    • Author Stylesheet 开发人员定义的CSS

    • User Stylesheet 用户自定义的CSS

      再考虑到重要声明,可以将样式如下排序(优先级从高到低):

    1. User Stylesheet (!important)

    2. Author Stylesheet (!important)

    3. Author Stylesheet (Normal)

    4. User Stylesheet (Normal)

    5. User Agent Stylesheet

  3. 按照选择器权重给所有样式声明排序

  4. 按照样式声明出现的顺序给其排序

    在相同权重下,样式声明离被设置元素越近优先级别越高,即“就近原则”。

    由于这个原因,才有了推荐的链接样式排序(link-visited-hover-active, LVHA)

    1
    2
    3
    4
    :link {color:blue;}
    :visited {color:purple;}
    :hover {color:red;}
    :active {color:orange;}

    上述顺序如果换成:

    1
    2
    3
    4
    :active {color:orange;}
    :hover {color:red;}
    :link {color:blue;}
    :visited {color:purple;}

    则任何链接都不会显示:hover:active样式。因为任何链接要么已访问,要么未访问,所以前两个样式会被覆盖。