CSS | 选择器的权重

前言:在之前做项目的过程中,有遇到因为CSS优先级导致页面页面上的样式无法生效的问题,所以打算写一篇文章记录下这块的知识。

选择器的匹配规则

之前的一篇文章中有提到过浏览器渲染的基本过程(链接),CSS选择器的匹配是发生在生成**渲染树(Render Tree)**的过程中。

  1. 浏览器为了节约性能,在解析CSS的过程中会从右往左读取CSS,这是因为防止从左往右读取的时候,会发生大量的回溯造成浏览器的性能损耗。
  2. 浏览器还会把不同类型的选择器(id、class、tag 及其他类型)归类到哈希表中,进一步减少查找基数

了解选择器的匹配原理,有利于我们理解其权重规则,对于编写简洁、高效的 CSS 代码非常有帮助。

CSS权重

浏览器通过优先级来判断哪些属性值与一个元素最为相关,从而在该元素上应用这些属性值。

优先级是基于不同种类选择器组成的匹配规则。------MDN-优先级

白话:CSS权重又被称为CSS优先级,优先级高则浏览器使用该样式的的优先级就更高

权重的规则

优先级就是分配给指定的 CSS 声明的一个权重,它由 匹配的选择器中的 每一种选择器类型的 数值 决定。

而当优先级与多个 CSS 声明中任意一个声明的优先级相等的时候,CSS 中最后的那个声明将会被应用到元素上。

当同一个元素有多个声明的时候,优先级才会有意义。因为每一个直接作用于元素的 CSS 规则总是会接管/覆盖(take over)该元素从祖先元素继承而来的规则。

备注: 文档树中元素的接近度(Proximity of elements)对优先级没有影响。

------MDN-优先级

简单来说就是有优先级的计算遵循几个规则:

  1. 权重不同的样式作用于同一个元素的时候,权重高的样式优先生效
  2. 权重相同的样式作用于一个元素的时候,后声明的样式生效
  3. 选择器在DOM树中的位置关系不会对权重产生影响
  4. 继承的CSS 样式不如为目标元素直接添加的CSS 样式
  5. 在同一组属性设置中标有!important规则的优先级最大(不推荐使用此关键字)

案例1:权重无视 DOM 树中的距离

比如下面这段代码:

CSS:

css 复制代码
body h1 {
  color: green;
}

html h1 {
  color: purple;
}

HTML:

html 复制代码
<html>
  <body>
    <h1>Here is a title!</h1>
  </body>
</html>

最后显示出来的样式:

上面这种情况body标签距离h1标签的距离更近但是最后显示出来的文字却是紫色的,这是因为此时二者的权重相同,而后声明的样式生效(规则2)

案例2:直接添加样式 vs. 继承样式

为目标元素直接添加样式,永远比继承样式的优先级高,无视优先级的遗传规则。

比如看下面这段代码:

CSS:

css 复制代码
#parent {
  color: green;
}

h1 {
  color: purple;
}

HTML:

html 复制代码
<html>
  <body id="parent">
    <h1>Here is a title!</h1>
  </body>
</html>

最后显示出来的样式:

虽然div#parent的优先级更高,但是这里的h1是继承自div#parentcolor属性,此时直接作用于h1标签的标签选择器会比div#parent的优先级更高。

CSS权重等级

一般情况下,CSS的权重等级有5种,按照由高到低的顺序来排列:

  1. !important关键字
  2. 内联样式
  3. id选择器
  4. 类选择器、属性选择器、伪类选择器(:where():is():not()比较特殊)
  5. 标签选择器、伪元素选择器

❕注意:

  1. 通配符选择器(*) 和 结合符(+>~)对权重没有影响。
  2. 尽量不要使用!important,特别是**在全站范围的 css **以及制作对外发布的插件的时候在插件代码当中使用,因为它改变了你样式表本来的级联规则,从而使其难以调试。
  3. 减少不必要的选择器嵌套,嵌套最好不要超过三级。大量的复合选择器,会影响选择器匹配的效率,同时也会增加 CSS 样式文件的体积,不易维护。
  4. 当出现大量嵌套时,可以指定一个更具体的类选择器来替换复合选择器。

!important关键字

当在一个样式声明中使用一个 !important 规则时,此声明将覆盖任何其他声明。虽然,从技术上讲,!important 与优先级无关,但它与最终的结果直接相关。使用 !important 是一个坏习惯,应该尽量避免,因为这破坏了样式表中的固有的级联规则 使得调试找 bug 变得更加困难了。当两条相互冲突的带有 !important 规则的声明被应用到相同的元素上时,拥有更大优先级的声明将会被采用。------MDN-优先级

非特殊情况下不要使用!important关键字,遵循**AONN(Always Only Never Never)**的准则:

  • Always 要优化考虑使用样式规则的优先级来解决问题而不是 !important
  • Only 只在需要覆盖全站或外部 CSS(例如引用的 ExtJs 或者 YUI )的特定页面 中使用 !important
  • Never 永远不要在全站范围的 CSS 上使用 !important
  • Never 永远不要在你的插件中使用 !important

可以使用的情况:

  • 在必要的情况下通过!important覆盖内联样式

    许多 JavaScript 框架和库都添加了内联样式。有时候可以用!important与优先级高的选择器一起使用,以重写覆盖这些内联样式。

  • 覆盖优先级高的选择器

    下面这种情况下,如果不使用 !important,第一条规则永远比第二条的优先级更高

    css 复制代码
    #someElement p {
      color: blue;
    }
    
    p.awesome {
      color: red;
    }

如何覆盖!important

  1. 添加一个优先级更高的样式

    再添加一条 带 !important 的 CSS 规则,再给这个给选择器更高的优先级(添加一个标签,ID 或类)··

    css 复制代码
       table td { height: 50px !important; }
    .myTable td { height: 50px !important; }
    #myTable td { height: 50px !important; }
  2. 使用相同的选择器,置于已有的样式后

    css 复制代码
    td { height: 50px !important; }
  3. 重写原来的样式,避免使用!important

    将 id 作为属性选择器的一部分而不是 id 选择器,下面的两个选择器现在具有相同的权重。在优先级相同情况下,后面定义的 CSS 样式会被应用。

    css 复制代码
    [id="someElement"] p {
      color: blue;
    }
    
    p.awesome {
      color: red;
    }

内联样式

语法:

html 复制代码
<div style="color: red;">测试</div>

id 选择器

语法

css 复制代码
#test {
  color: red;
}

类选择器、属性选择器、伪类选择器

语法:

css 复制代码
.demo {}
[type="text"] {}
div:hover {}
div:first-child {}

:where():is():not()

  • :not():is():在计算权重的时候不会被视作伪类,而是将参数中的选择器作为判定权重的标准

    参考:链接

  • :where():该伪类的权重始终为0

  • 补充::is():where()的区别在于:is()它以权重最高参数的也就是选择器判定权重,而:where()的权重为0

    参考:链接

标签选择器、伪元素选择器

css 复制代码
div {}
div:before {}
div:after {}

权重的计算方法

当遇到比较复杂的选择器的时候,需要做的是逐个比较每个选择器的权重大小,然后计算出来。

比如,现在有一个权重表格:

!important关键字 内联样式 id选择器 类、伪类、属性 标签、伪元素
0 0 0 0 0

现在有这样一个CSS

css 复制代码
#testDiv li.class a[href]{}

问:该CSS的权重是多少?

解:

  1. 存在一个id选择器,**[id选择器]**权重+1
  2. 存在类选择器、属性选择器,**[类、伪类、属性]**权重+2
  3. 存在两个标签标签选择器,**[标签、伪元素]**权重+2

答:

!important关键字 内联样式 id选择器 类、伪类、属性 标签、伪元素
0 0 1 2 2

该属性的权重为0-0-1-2-2

实际上对于CSS样式权重,还可以参考下面这张图理解,权重的计算过程与上面的案例是一样的:

参考文献

相关推荐
y先森2 分钟前
CSS3中的伸缩盒模型(弹性盒子、弹性布局)之伸缩容器、伸缩项目、主轴方向、主轴换行方式、复合属性flex-flow
前端·css·css3
前端Hardy3 分钟前
纯HTML&CSS实现3D旋转地球
前端·javascript·css·3d·html
susu10830189116 分钟前
vue3中父div设置display flex,2个子div重叠
前端·javascript·vue.js
IT女孩儿1 小时前
CSS查缺补漏(补充上一条)
前端·css
吃杠碰小鸡2 小时前
commitlint校验git提交信息
前端
虾球xz3 小时前
游戏引擎学习第20天
前端·学习·游戏引擎
我爱李星璇3 小时前
HTML常用表格与标签
前端·html
疯狂的沙粒3 小时前
如何在Vue项目中应用TypeScript?应该注意那些点?
前端·vue.js·typescript
小镇程序员3 小时前
vue2 src_Todolist全局总线事件版本
前端·javascript·vue.js
野槐3 小时前
前端图像处理(一)
前端