CSS Specificity

层叠样式表优先级

November 6, 2018

页面样式渲染

渲染树(Render Tree)

对于一个网页(包括小程序的Page): HTML解析成一个DOM (Document Object Model)树,样式表会解析成一个 CSSOM(CSS Object Model)树, 二者结合形成一颗渲染树。

渲染树上的样式即为最终用来渲染呈现的样式(Chrome Computed style)。

渲染节点属性选择

  • 自定义样式
    • 代码定义
    • 客户端设置(浏览器默认样式)
  • 继承(父级样式)
  • CSS标准

对于渲染树上任意一个节点属性的计算:

  1. 如果这个节点的属性已经在样式表中定义了,优先采用定义的样式(包括代码中定义和浏览器的默认样式),对于多个定义的优先级会在后面详细解释;
  2. 如果没有定义,该属性默认可以继承,则向上递归查找祖先定义的该属性;
  3. 如果未定义,默认不能继承则采用标准的属性值(一般都会有默认属性,不会到这一步)

示例 CSS 样式选择.

样式选择优先级

1样式声明的权重

  • 内联样式
  • 样式选择器样式 (包括默认浏览器默认样式)
    • #ID选择器
    • .Class选择器,属性选择器,伪类选择器
    • Tag标签选择器,伪元素选择器
  1. 内联样式之间作用与节点,具有最高的权重,包括style=""和JS动态修改element的样式。
  2. CSS定义中的ID选择器(如#id{})的权重次之;在CSS定义中具有最高的权重;
  3. CSS中类选择器(.class{})和属性选择器([attribute]{})以及伪类选择器(:hover)等具有相同的权重;
  4. 标签选择器(h1{})和伪元素选择器(::before)具有相同的权重

通配选择符(universal selector)(*), 关系选择符(combinators) (+,>,~, )和 否定伪类(negation pseudo-class)(:not()) 无权重。

总结,根据下面关系,应用权重最高的定义。

inline > #id > .class = [attribute] = :pseudo-class > tag = ::pseudo-element > *

See the Pen 定义优先级.

如果选择器级联操作,计算级联权重

2级联样式权重

前面提到,CSS定义中有3类权重id选择器,class选择器,和标签选择器。

分别统计在一个属性中,三中类型出现的频次, 选ID频次最高的,如果有多个相同则再选class权重最高的依次类推。

例如

/*1*/
#i > .content {
    color:red;
}
/*2*/
.c > #i2 {
    color:green;
}
/*3*/
.c > .c2.c3{
    color:yellow;
} 
/*4*/
#ii #ii2{
    color:blue;
}

其中1和2的权重一样(一ID一class),4的权重最高(俩个ID)

如果最高权重的仍有,多个根据出现属性确定优先级。

示例 CSS 级联权重.

3定义顺序

  • inline
  • media query
  • 代码定义或者浏览器默认,以最后出现优先

4!important

!important声明高于所有非!important的属性,具有最高的优先级,

多个!important属性时通过上述再进行权重比较。

总结

完整优先级判断

属性计算的优先流程(非实际计算过程)

实践原则

  1. 避免使用#id 选择器
    • 避免在CSS中使用
    • 仅在JS操作相关内容中使用
  2. 慎用!important
    • 共用组件和库中应该避免使用!important
    • 能不用!important的则不用!important
    • 使用!important:
      • 无法正常维护的代码项目中
      • 只能在外层插入样式,不能修改既有任何代码的情况
      • 功能单一的工具性CSS样式(如控制文本居中.text-center{text-align:center!important});
  3. 善用[attribute]:pseudo-class
    • 尽量利用attribute控制样式(语义一致性)如: button[disabled],.link:hover
  4. inline一版是JS动态修改样式使用。

参考