CSS选择器权重计算

6/30/2020 CSS

# css 权重概念

浏览器通过优先级来判断哪一些属性值与一个元素最为相关,从而在该元素上应用这些属性值。优先级是基于不同种类选择器组成的匹配规则。

# 普通权重

一般来说,css 的默认权重都是这样:权重从高到低,高的覆盖低权重的 css

  1. 在属性后面使用 !important 会覆盖页面内任何位置定义的元素样式
  2. 作为 style 属性写在元素标签上的内联样式
  3. id 选择器
  4. 类选择器
  5. 伪类选择器
  6. 属性选择器
  7. 标签选择器
  8. 通配符选择器
  9. 浏览器自定义

# 复杂场景权重计算方式

在基于普通权重的情况下,css 权重又该如何计算? 我们先作出一个 假设。注意是假设,用这段数字方便我们理解权重的计算

选择器 行内样式 id 选择器 类,属性选择器和伪类选择器 标签选择器、伪元素
权重值 1000 100 10 1

# 怎么理解这些权重值?

假设现在有一段 css #box .left div{ color:#4e98bb; }
可以想象到 html 结构如下:

<div id="box">
  <div class="left">
    <div>我是被计算的div</div>
  </div>
</div>
1
2
3
4
5

那么这段 css 权重值计算出来是多少?根据上面的对照表,一次得出权重值,然后相加得出:
100(id 选择器) + 10(类选择器) + 1(标签选择器) = 111

# 就这?叫复杂?来点实战

最后 color 渲染了什么颜色?为什么

<style>
  #box .left div {
    color: blue; /*蓝*/
  }
  .box-content .left div {
    color: green; /*绿*/
  }
  #box-content .left div {
    color: purple; /*紫*/
  }
  .left {
    color: red; /*红*/
  }
  .left div {
    color: yellow; /*黄*/
  }
</style>

<div class="box-content" id="box-content">
  <div id="box">
    <div class="left">
      <div>我是被计算的div</div>
    </div>
  </div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
查看答案和计算过程

最后渲染:purple 紫色

分别计算权重值:

  • green 绿:2 * class 选择器 = 20
  • blue 蓝:1 * id 选择器 + 1*class 选择器 + 1*标签选择器 = 111
  • purple 紫: 1 * id 选择器 + 1*class 选择器 + 1*标签选择器 = 111
  • red 红:1*class 选择器 = 10
  • yellow 黄:1*class 选择器 + 1*标签选择器 = 11

按照权重的计算方式:权重最高的就是bluepurple

最后为什么是 紫色 ?

这就得再次细化分析:

“权重相同情况下”,css 顺序越靠后就会覆盖前面的 css 规则

这里注意。一定是“权重相同情况下”,后面加载的 css 才会覆盖前面的。

再看一个示例:

<style>
  #box .child {
    color: blue;
  }

  #box .left {
    color: purple;
  }
</style>

<div class="box-content" id="box-content">
  <div id="box">
    <div class="left">
      <div>
        <div class="child">我是被计算的div</div>
      </div>
    </div>
  </div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

这个时候,如果按上面的计算规则是否符合“权重相同情况下”,这时候 purple 是排在 blue 后面的。不过最后渲染的却是blue

这是因为,层级结构也会影响最后渲染的权重。如何理解这个层级结构?上面的 demo 就很清晰了,因为一个只控制到了 .left 的层级,而另外一个则是更精确的控制到了 .child 的层级。所以控制的更精确的层级对应的权重也会相应的提升。

层级结构指的是css规则的最后一级距离目标控制的div的远近。假设我们把 #box .child 改为 #box-content .child ,虽然顶层的选择器更远了一点,但是只要 .child 还是距离最近的,那么就不会影响渲染结果。

# 小结一下

  1. css 最终的计算规则是按权重的,权重最高的那段 css 就会被渲染出来
  2. 权重相同情况下,根据 层级结构选择越接近的话就会选择最相近的一个选择器的 css 样式进行渲染
  3. 权重相同 & 层级结构选择也相同的情况下。则会根据 css 的编写顺序,遵循后面覆盖前面的原则

# 来一堆例子计算下权重

能说出一下的计算过程吗?

*             {}  /* 0 */
p             {}  /* 1 */
a:hover       {}  /* 20 */
ul li         {}  /* 2 */
ul li+li      {}  /* 30 */
h1+input[type=hidden]{} /* 12 */
ul ol li.active   {}  /* 13 */
#ct .box p        {}  /* 111 */
div#header::after  {}  /* 102 */

/* 行内样式style */
style=""  /* 1000 */
1
2
3
4
5
6
7
8
9
10
11
12
  • 多次出现的选择器相加,可以重复叠加(比如 li+li是相当于 2 个标签选择器计算,这里可以记为 2)
  • [type=hidden]属于属性选择器,权重比标签选择器还要高
  • 注意区分伪类,和伪元素,伪类的权重比伪元素高

这些例子只是举例说明从css的权重计算。如果权重相同的情况下,真实的渲染还要考虑层级结构、css渲染顺序问题。所以不能一概而论。

# 如何区分伪类,伪元素?

伪类::hover 伪元素:::after

  • 伪类并不会添加内容,只是一个样式的补充,通常:hover,:focus 等都是伪类,他们不会改变 html 结构,不会添加节点
  • 伪元素:就好比 after 这种。使用后,必须添加 content 属性,并且 content 属性的内容,会渲染在 html 上,就好像我们真实的 html 元素,只是用 css 添加的

# 总结

  • 以上的计算方式只是作出了假设,真实的 css 计算比这个复杂得多,作出这个假设只是为了方便理解

  • 以后覆盖 css 样式,就可以根据这个规则,适当添加 class 选择器的数量,就可以避免写行内样式或者用 !important 之类的了

  • 除了上述描述的选择器权重,通配符和浏览器的样式默认权重都是最低的,,低的可以忽略不计那种~

有没有最高权重的选择器?

有!<div style="color:red !important;"></div>
能写出这种的,基本都已经被打死了把

最后一个小提示

引入 css 的方式还有一个:@import,在正常情况下,不要使用 import,他会让我们引用的 CSS 文件中的样式覆盖当前的样式。

Last Updated: 3/17/2024, 2:50:09 PM