css 权重计算

944 阅读5分钟

css 权重概念

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

普通权重

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

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

复杂场景权重计算方式

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

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

怎么理解这些权重值?

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

<div id="box">
  <div class="left">
    <div>我是被计算的div</div>
  </div>
</div>

那么这段 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>

::: details 查看答案和计算过程

最后渲染: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>

这个时候,如果按上面的计算规则是否符合“权重相同情况下”,这时候 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 */
  • 多次出现的选择器相加,可以重复叠加(比如 li+li是相当于 2 个标签选择器计算,这里可以记为 2)
  • [type=hidden]属于属性选择器,权重比标签选择器还要高
  • 注意区分伪类,和伪元素,伪类的权重比伪元素高

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

如何区分伪类,伪元素?

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

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

总结

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

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

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

::: tip 有没有最高权重的选择器?
有!<div style="color:red !important;"></div>
能写出这种的,基本都已经被打死了把 :::

::: tip 最后一个小提示

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

:::