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样式权重,还可以参考下面这张图理解,权重的计算过程与上面的案例是一样的:

参考文献

相关推荐
Dread_lxy几秒前
vue 依赖注入(Provide、Inject )和混入(mixins)
前端·javascript·vue.js
涔溪44 分钟前
Ecmascript(ES)标准
前端·elasticsearch·ecmascript
榴莲千丞1 小时前
第8章利用CSS制作导航菜单
前端·css
奔跑草-1 小时前
【前端】深入浅出 - TypeScript 的详细讲解
前端·javascript·react.js·typescript
羡与1 小时前
echarts-gl 3D柱状图配置
前端·javascript·echarts
guokanglun1 小时前
CSS样式实现3D效果
前端·css·3d
咔咔库奇1 小时前
ES6进阶知识一
前端·ecmascript·es6
渗透测试老鸟-九青2 小时前
通过投毒Bingbot索引挖掘必应中的存储型XSS
服务器·前端·javascript·安全·web安全·缓存·xss
龙猫蓝图2 小时前
vue el-date-picker 日期选择器禁用失效问题
前端·javascript·vue.js
fakaifa2 小时前
CRMEB Pro版v3.1源码全开源+PC端+Uniapp前端+搭建教程
前端·小程序·uni-app·php·源码下载