CSS 权重详解

作者: 西山以南 | 来源:发表于2019-06-17 17:59 被阅读44次

对于 CSSer 来说,多多少少都会遇到过 “样式规则不生效?”、“样式规则被覆盖?” 等等问题,这些都与 CSS 权重有关系。

选择器匹配原理

在此之前,容我先简单介绍浏览器是怎么通过各种选择器,把样式规则和 DOM 元素扯上关系的。

浏览器中存在着专门的渲染引擎来渲染 HTML 文档。这里以 Webkit 内核为例,在启动渲染流程时,引擎一方面会解析 HTML 文档,构建 DOM 节点树(DOM Tree,另一方面会解析样式文件生成 样式规则(Style Rules,然后结合分析 DOM 树和样式规则生成 渲染树(Render Tree,最后 布局绘制 出 UI 界面。

Webkit 渲染流程(摘自 https://www.html5rocks.com/en/tutorials/internals/howbrowserswork/)

CSS 的选择器匹配就发生在 渲染树 的构建过程。浏览器会从 DOM 树的根节点开始遍历每个可见节点,对于每个可见节点都会在规则表中查找适配的样式规则。那么,如此庞大的样式数据和复杂的选择器结构,渲染引擎是怎么寻找到适配当前元素的样式规则呢?

请看下面这个复合选择器。如果引擎是按照从左向右的顺序匹配选择器,将会导致大量 回溯 的发生:先是在当前节点到 DOM 树跟节点的路径上寻找 div 元素,然后沿着分支路径继续往下找第二个 div 元素,如果当前路径找不到,就得回退到上一个 div 元素尝试另一条分支路径。如此往复,对性能损耗将会非常严重。

div div span .text {}

所以,引擎是采取 从右向左 的顺序来匹配选择器。也就是 从最具体的选择器开始,如果与当前节点不匹配,则直接抛弃该条规则;如果匹配,只需要沿着路径往上确认其他选择器是否也匹配,这样做可以大大减少无效的匹配数,提高性能。除此之外,引擎还会把不同类型的选择器(idclasstag 及其他类型)归类到哈希表中,进一步减少查找基数。

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

CSS 权重

通过不同的方式(内联样式外部样式表)、不同类型的选择器组合针对某个元素声明样式规则时,如何决定最终哪个声明会被应用到元素上?这就涉及到 CSS 权重(也指优先级,Specificity)

围绕 CSS 权重主要有以下三条规则:

  • 权重不同的样式规则作用于同一元素时,权重高的规则生效;

  • 权重相同的样式规则作用于同一元素时,后声明的规则生效;

    选择器在 DOM 中的位置关系不会对规则产生影响。

    <html>
      <head>
        <style>
        body div {
          color: red;
        }
        html div {
          color: blue;
        }
        </style>
      </head>
    
      <body>
        <div>测试</div>
      </body>
    <html>
    

    这里的 body 标签元素在 DOM 中离目标 div 更近,但最后还是按照样式规则的声明顺序来决定。

  • 直接作用于元素的样式规则优先级高于从祖先元素继承的规则;

    <html>
      <head>
        <style>
        #parent {
          color: red;
        }
        span {
          color: blue;
        }
        </style>
      </head>
    
      <body>
        <div id="parent">
          <span>测试</span>
        </div>
      </body>
    <html>
    

CSS 权重等级

如何比较不同选择器的权重高低?这里划分成 5 个权重等级,按照等级 由高到低 的顺序:

  • !important 关键字

  • 内联样式

    <div style="color: #fff;">测试</div>
    
  • id 选择器

    #demo {}
    
  • 类选择器属性选择器伪类选择器

    .demo {}
    [type="text"] {}
    div:hover {}
    div:first-child {}
    

    需要注意,否定伪类(:not()比较特殊,它不会对权重产生影响,但是 否定伪类内部的选择器会影响权重

    <html>
      <head>
        <style>
          div#demo span {
            color: red;
          }
          div:not(#demo) span {
            color: blue;
          }
        </style>
      </head>
    
      <body>
        <div id="demo">
          <span>普通 demo</span>
          <div id="pseudo">
            <span>否定伪类 demo</span>
          </div>
        </div>
      </body>
    <html>
    

    实例中,:not(#demo) 的权重值和 #demo 的权重值是相等的,所以后面声明的样式规则成功生效。

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

    div {}
    div:before {}
    div:after {}
    

除了上述的选择器之外,通配符选择器(*结合符(+>~对优先级没有影响。

对于复杂的复合选择器,我们需要逐个等级比较权重大小,不允许跨越等级比较。为了方便计算,我们可以把权重值具象化,每出现一个选择器就在其对应的等级区间中权重值加 1,参考下面实例:

* {}               /* 权重值 0-0-0-0-0 */
div {}             /* 权重值 0-0-0-0-1 */
div h1+h2 {}       /* 权重值 0-0-0-0-3 */
div, ... div {}    /* 权重值 0-0-0-0-n */
#demo a:hover {}   /* 权重值 0-0-1-1-1 */

国外大神 把 CSS 权重的计算模拟成海洋生物链,选择器组合权重越大则在生物链位置越高,非常浅显生动,建议收藏。

图片转自 https://specifishity.com/

建议

在充分了解 CSS 选择器匹配原理和权重规则之后,在编写 CSS 代码时不妨多注意以下细节:

  • 尽量不要使用 !important,尤其是在 对外提供的插件全站范围的样式表 中,这会对模块代码中的样式覆盖带来非常大的麻烦。

    !important 关键字的权重值为 1-0-0-0-0,只需要按照权重规则继续累加权重值即可覆盖该样式属性。

    <html>
      <head>
        <style>
          div {
            color: red !important;
          }
          /* 通过 id选择器 增加权重 */
          #demo {
            color: blue !important;
          }
        </style>
      </head>
    
      <body>
        <div id="demo">测试</div>
      </body>
    <html>
    
  • 减少不必要的选择器嵌套,嵌套最好不要超过三级。大量的复合选择器,会影响选择器匹配的效率,同时也会增加 CSS 样式文件的体积,不易维护。

    当出现大量嵌套时,我们可以指定一个更具体的类选择器来替换复合选择器。

    body div ul li span {}
    .li {}
    

Reference

相关文章

  • CSS 权重详解

    对于 CSSer 来说,多多少少都会遇到过 “样式规则不生效?”、“样式规则被覆盖?” 等等问题,这些都与 CSS...

  • 归零——CSS-第四天

    CSS学习 CSS权重 选择器 权重...

  • css flex布局详解

    css flex布局详解 css flex布局详解1css flex布局详解2

  • CSS权重

    原文 博客原文 大纲 1、CSS层叠2、CSS权重3、权重等级4、权重的规则5、!important 1、CSS层...

  • CSS选择器

    CSS 元素选择器CSS 选择器分组CSS 类选择器详解CSS ID 选择器详解CSS 属性选择器详解CSS 后代...

  • 前端面试题整理

    css相关 1、css定义的权重: 标签的权重为1,class的权重为10,id的权重为100如果权重相同,则最后...

  • CSS权重

    CSS权重:1、权重决定了你css规则怎样被浏览器解析直到生效。“css权重关系到你的css规则是怎样显示的”。2...

  • 前端方法

    css 权重 !important具有最高权重 如何和何时使用CSS的!important https://www...

  • css选择器权重

    css选择器权重示例: .html .css

  • web前端基础案例-鼠标悬停图文切换效果

    效果知识点: html/css布局思维,定位,浮动详解,css3动画详解,css3选择器详解, 通用样式与封装,企...

网友评论

    本文标题:CSS 权重详解

    本文链接:https://www.haomeiwen.com/subject/cgjatctx.html