CSS选择器

写在前面

最近在群内,收到大佬出的一个小题目,关于CSS选择器,基于复习和学习新知识(或许不是新知识,而是自己未做了解~)的目的,遂有了以下的文章内容

题目

相关代码如下,.foo的 DOM 内容是什么颜色?

  <p class="foo">Lorem ipsum</p>
@layer test;
.foo.foo {
  color: red;
}

:is(.foo, #foo) {
  color: green;
}

:where(.foo, #foo) {
  color: yellow;
}

.foo {
  color: blue;
}

@layer test {
  p {
    color: purple;
  }
}

当然,我的第一反应是 red,当然是错误的~,正确答案是green

答案

我们通过浏览器的开发者工具Elements最后的styles来看下结果。

selectors01

通过上图可以看出最先被干掉的是 @layer test 内的样式,然后是:where()内的样式,.foo.foo.foo的样式优先级不难理解,重复书写 class 类名选择器可以提升优先级,最后是:is()内的样式优先级最高,渲染成绿色。

通过日常的 CSS 代码书写和相关知识的阅读学习,关于元素选择器、类名选择器、属性选择器和逻辑伪类选择器相关的优先级应该是有个基础的认识。对于大佬题目中的@layer:is():where()则在日常开发中未有涉及或了解。

:where() 和 :is()

这两个选择器都是可容错选择器,接受参数均为可容错选择器列表,并且匹配规则均是任何一条规则选中的元素。 区别在于 :where():is() 匹配后的样式优先级计算规则不同,:where() 优先级总是 0,而 :is() 是由接受参数-选择器列表中的最高优先级决定,这也就不难理解 :where() 先被干掉,对于浏览器来说,他的优先级是 0,而 .foo.foo.foo 的优先级分别是10和20,自然按优先级大小依次干掉先前的,最后是 :is() 的优先级因为 .foo 匹配成功,最后优先级由列表中 #foo 决定,为 100。最后 .foo 渲染为绿色。

关于 :where():is() 的其他妙用,可以参考MDN上的一些介绍,在此,只因优先级触发的兴趣,未做其他了解,则不做赘述,感兴趣的童鞋,请自行前往~

@layer

这是个什么?大佬的博客内写了这样一句话:

@layer诞生的背景

同一个 CSS 上下文中,有些 CSS 声明需要设置低优先级,且这种优先级不受选择器权重的影响。
@layer 规则就是解决上面这种场景应运而生的。
可以让 CSS 声明的优先级下降一整个级联级别。

@layer {} 声明匿名的级联层,声明时则在{}内书写规则,之后无法为匿名级联层添加规则;

@layer layer-name {} 声明具名的级联层,同时书写规则,之后也可以继续添加规则;

@layer layer-name1, layer-name2 声明具名的级联层,不添加规则,可配置多个,先后顺序代表优先级由低到高;

@layer 可以嵌套使用,优先级比较时参考外层先比较后比较内层。

@layer 优先级

  • 级联层与不分层样式
    当级联层中设置样式时,优先级会降低,级联层外的样式会覆盖级联层中的样式,即优先级如 答案 内容所示
  • 级联层间(未声明顺序)
    按照声明的先后顺序,优先级由低到高,自上而下,与普通的样式覆盖逻辑类似,
    如题目代码改成如下:
    @layer test1 {
      .foo.foo {
        color: red;
      }
    
      :is(.foo, #foo) {
        color: green;
      }
    
      :where(.foo, #foo) {
        color: yellow;
      }
    
      .foo {
        color: blue;
      }
    }
    @layer test {
      p {
        color: purple;
      }
    }
    
    此时最终的渲染颜色为purpleselectors02
  • 级联层间(已声明顺序)
    已声明顺序的情况下,则按照声明顺序指定优先级,先声明的优先级越低,自低至高排序
    将上述代码改动一下,在顶部添加如下代码:
    @layer test, test1;
    
    此时最终的渲染颜色又变成了greenselectors03

选择器优先级的计算

通篇文章读到这里时,关于了解到的:where():is()的优先级计算,在上述答案解析时,已经有10100等表述,而在大佬公布完答案后,关于优先级的计算,可以通过devtools看到specificity,我们可以发现浏览器中显示的关于优先级是一个三元组(a, b, c)。关于这部分内容则通过大佬的指引,找到如下内容:

  • 在 selectors Level3 中,计算规则如下: selectors04

  • 在 selectors Level4 中,计算规则如下: selectors05 可以看出,在 selectors Level4 中,优先级的计算规则,可以理解为“按位比较”。

    当然,更多的内容以及“256个class选择器可以覆盖 1 个 id选择器样式优先级 ”,涉及位运算相关知识内容,可以通过源码去查看,而对于 Due to storage limitations, implementations may have limitations on the size of A, B, or C. If so, values higher than the limit must be clamped to that limit, and not overflow. 这句话则直接表明了规范中为避免溢出,浏览器会截取掉超出的部分,如果你重复 class类名,超过 255次后,则被直接截取掉,可以自己在浏览器内进行尝试~ selectors06

参考资料

最近更新时间: