关于 CSS 选择器权重,99% 的人都理解错了!

2024年 5月 7日 115.3k 0

CSS 选择器的权重(特异性)是确定在多个选择器应用于同一元素时,哪个选择器的样式会最终生效的关键因素。然而,关于 CSS 选择器特异性的理解,常常存在一些常见的误解。本文将探讨这些误解,并帮助大家理解 CSS 选择器的权重。

误解一:权重是一个数字

CSS 选择器的权重并不是一些数字。所以,计算元素的权重时,并不是简单的将权重数值相加就可以了。

CSS 选择器的权重由三个部分组成,表示为 (a, b, c),其中 a、b、c 分别代表了不同选择器类型的权重。具体规则如下:

  • ID选择器:权重值为(1, 0, 0),通过元素的ID选择器来匹配的样式。
  • 类选择器、属性选择器和伪类选择器:权重值为(0, 1, 0),类选择器(如.example)、属性选择器(如[type="text"])和伪类选择器(如:hover)具有相同的权重。
  • 元素选择器和伪元素选择器:权重值为(0, 0, 1),元素选择器(如p)和伪元素选择器(如::before)具有相同的权重。

注意:通配符选择器(如 *)、子选择器(如 >)、相邻兄弟选择器(如 +)和兄弟选择器(如 ~)对权重没有贡献,即它们的权重为 (0,0,0)。

权重计算规则:

  • 从左到右进行比较:首先比较最高位(内联样式),如果相同,则比较下一位,依此类推。例如(1, 0, 0)的优先级高于(0, 1, 0),而(0, 1, 0)的优先级高于(0, 0, 1)。
  • 权重相加:每个组成部分的权重是独立计算的,并且不会累加。比如,一个选择器中有两个类选择器(.class1.class2)并不会使其权重变为(0,2,0),而是仍然保持为(0,1,0)。同样,一个选择器中有一个ID选择器和一个类选择器(#id.class)的权重是(1,1,0),而不是(2,0,0)。
  • !important 规则:如果在声明中使用了 !important,它会覆盖其他所有的特异性。但需要注意的是,!important 只在同一来源的样式中有效。如果来自用户代理样式表(浏览器默认样式)或用户样式表的 !important 规则与来自作者样式表的普通规则冲突,那么用户代理样式表或用户样式表的 !important 规则会生效。
  • 来源顺序:如果两个规则的特异性相同,并且都没有使用 !important,那么后出现的规则会覆盖先出现的规则(即“后来者居上”的原则)。
  • 例如:

    /* 权重为 (0,0,1) */  
    div { color: red; }  
    
    /* 权重为 (0,1,0) */  
    .class1 { color: green; }  
    
    /* 权重为(1,0,0) */  
    #id1 { color: blue; }  
    
    /* 权重为(1,1,0)(因为 ID 选择器的权重高于类选择器)*/  
    #id1.class1 { color: purple; }  
    
    /* 权重为(0,1,0),因为只有一个类选择器 */  
    .class1 { color: red; }  
      
    /* 权重为(0,1,0),即使有两个类选择器,但它们的权重不会相加 */  
    .class1.class2 { color: blue; }  
      
    /* 权重为(1,1,0),因为一个ID选择器和一个类选择器的组合 */  
    #id1.class1 { color: green; }  
      
    /* 权重为(0,1,0),因为有三个类选择器,但每个类选择器的权重仍然是(0,1,0) */  
    .class1.class2.class3 { color: purple; }

    在上面的例子中,即使选择器中包含多个相同的组成部分(如类选择器),每个组成部分的权重仍然是独立的,并且不会累加。因此,在选择器冲突时,特异性更高的选择器将覆盖特异性较低的选择器。如果特异性相同,则后出现的规则会覆盖先出现的规则(即“后来者居上”的原则)。

    详细来看看最后一个例子:

    对于选择器 .class1.class2.class3,其特异性(权重)的计算方式如下:

    • 该选择器包含三个类选择器(.class1、.class2 和 .class3)。
    • 在CSS特异性计算中,每个类选择器都贡献(0,1,0)的特异性值。
    • 由于特异性值不会跨类型累加,我们只需关注类选择器这一位(即第三位)上的数量。
    • 在这个例子中,有三个类选择器,但每个类选择器在类选择器这一位上的值仍然是 1。

    但是,这并不意味着三个类选择器加起来就是 3。实际上,在选择器的特异性计算中,我们不会将类选择器这一位上的值相加。我们只需记录存在多少个类选择器(在这个例子中是三个)。然而,在描述特异性时,我们通常(0,3,0)不直接写出这样的表示法,因为按照标准的特异性表示法,我们只需指出在类选择器这一位上有三个单位(即 0,1,0 出现了三次)。

    但是,为了明确和避免混淆,当我们谈论这种由多个同类选择器组成的选择器的特异性时,我们可能会说它在类选择器这一位上的特异性“权重”相当于(0,3,0)(尽管这不是标准的表示法)。不过,在比较选择器的特异性时,我们只需记住它在类选择器这一位上有三个单位。

    因此,.class1.class2.class3 的特异性(权重)按照标准的表示法是 (0,1,0)(但因为有三个类选择器,所以在类选择器这一位上的“等效权重”可以理解为三个单位)。

    误解二:使用style属性会增加权重

    很多人认为,在 HTML 元素上直接使用style属性来定义 CSS 样式会增加样式权重。

    在 HTML 元素上直接使用style属性并不会增加元素的特异性。实际上,style 属性定义的样式具有最高的优先级,这通常被称为“内联样式”或“行内样式”。但这种高优先级并非来源于特异性的计算,而是源于CSS层叠和冲突解决机制中的一个特殊规则。

    CSS层叠的优先级规则中,style属性(内联样式)的优先级高于其他任何在样式表中定义的样式规则,无论这些样式规则使用了何种选择器(ID、类、元素等)。但请注意,这种优先级与特异性是两个不同的概念。

    • 特异性:用来确定哪些样式规则会应用到元素上的机制。特异性是一个由三个部分组成的权重值当两个或更多的样式规则都适用于同一个元素时,浏览器会根据这些规则的特异性来决定哪个规则会最终应用到该元素上。
    • 优先级:在特异性相同的情况下,用来确定哪个样式规则会生效的机制。这时,会按照以下顺序来确定优先级,在优先级上,用户样式会覆盖用户代理样式,而作者样式会覆盖用户样式(除非用户样式使用了!important):

    内联样式

    作者的样式表

    重要的作者样式

    普通的作者样式

    用户代理样式(User Agent Stylesheet):浏览器的默认样式,如默认字体大小、颜色等。

    用户样式(User Styles):通过浏览器设置或扩展自定义的样式。

    作者样式(Author Styles):在样式表中定义的样式。

    在作者定义的样式中,内联样式具有最高的优先级,即使其他样式规则具有更高的特异性。但请注意,这并不意味着内联样式具有更高的特异性;它只是在优先级上高于其他样式。因此,style属性并不会增加元素的权重。

    误解三:使用!important会增加权重

    我们知道,在 CSS 中使用 !important 会使得样式的优先级最高。不过,在 CSS 声明中使用 !important 并不会增加其特异性。

    特异性(权重)是一个由选择器类型决定的权重系统,用于确定在多个样式规则应用于同一元素时,哪个规则会被优先应用。而!important则是一个覆盖机制,用于改变声明的优先级,使其在CSS的层叠顺序中具有更高的权重。

    当浏览器需要确定一个元素的最终样式时,它会按照以下步骤进行:

  • 计算特异性:首先,浏览器会计算每个应用于该元素的 CSS 规则的特异性。特异性越高的规则,其优先级越高。
  • 比较来源:如果两个或多个规则具有相同的特异性,浏览器会进一步比较这些规则的来源。通常,用户定义的样式(如浏览器扩展或用户样式表)会覆盖作者定义的样式(即网页开发者的样式表),而作者定义的样式会覆盖用户代理样式(即浏览器的默认样式)。
  • 考虑!important:如果两个或多个规则具有相同的特异性和来源,并且其中至少有一个使用了!important,则使用了!important的规则会覆盖没有使用!important的规则。
  • 比较顺序:如果两个或多个规则具有相同的特异性、来源,并且都没有使用!important,或者都使用了!important,则最后定义的规则会覆盖先前定义的规则。
  • 因此,!important并不改变特异性,而是在特异性比较之后,作为一个额外的优先级判断依据。使用!important应该谨慎,因为它会破坏CSS的层叠和特异性规则,使得样式更难于维护和调试。在可能的情况下,最好通过优化选择器和组织样式规则来避免使用!important。

    相关文章

    JavaScript2024新功能:Object.groupBy、正则表达式v标志
    PHP trim 函数对多字节字符的使用和限制
    新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
    使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
    为React 19做准备:WordPress 6.6用户指南
    如何删除WordPress中的所有评论

    发布评论