由题目引发的CSS选择器优先级学习

写在前面

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

题目

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

html 复制代码
  <p class="foo">Lorem ipsum</p>
css 复制代码
@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来看下结果。

通过上图可以看出最先被干掉的是 @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 优先级

  • 级联层与不分层样式
    当级联层中设置样式时,优先级会降低,级联层外的样式会覆盖级联层中的样式,即优先级如 答案 内容所示

  • 级联层间(未声明顺序)
    按照声明的先后顺序,优先级由低到高,自上而下,与普通的样式覆盖逻辑类似,
    如题目代码改成如下:

    css 复制代码
    @layer test1 {
      .foo.foo {
        color: red;
      }
    
      :is(.foo, #foo) {
        color: green;
      }
    
      :where(.foo, #foo) {
        color: yellow;
      }
    
      .foo {
        color: blue;
      }
    }
    @layer test {
      p {
        color: purple;
      }
    }

    此时最终的渲染颜色为purple

  • 级联层间(已声明顺序)
    已声明顺序的情况下,则按照声明顺序指定优先级,先声明的优先级越低,自低至高排序
    将上述代码改动一下,在顶部添加如下代码:

    css 复制代码
    @layer test, test1;

    此时最终的渲染颜色又变成了green

选择器优先级的计算

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

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

可以看出,在 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次后,则被直接截取掉,可以自己在浏览器内进行尝试~

参考资料

相关推荐
代码搬运媛20 小时前
Jest 测试框架详解与实现指南
前端
counterxing21 小时前
我把 Codex 里的 Skills 做成了一个 MCP,还支持分享
前端·agent·ai编程
wangqiaowq21 小时前
windows下nginx的安装
linux·服务器·前端
之歆21 小时前
DAY_12JavaScript DOM 完全指南(二):实战与性能篇
开发语言·前端·javascript·ecmascript
发现一只大呆瓜21 小时前
Vite凭什么这么快?3分钟带你彻底搞懂 Vite 热更新的幕后黑手
前端·面试·vite
Maimai1080821 小时前
React如何用 @microsoft/fetch-event-source 落地 SSE:比原生 EventSource 更灵活的实时推送方案
前端·javascript·react.js·microsoft·前端框架·reactjs·webassembly
kyriewen1 天前
产品经理把PRD写成“天书”,我用AI半小时重写了一遍,他当场愣住
前端·ai编程·cursor
humcomm1 天前
元框架的工作原理详解
前端·前端框架
canonical_entropy1 天前
Attractor Before Harness: AI 大规模开发的方法论
前端·aigc·ai编程
zhangxingchao1 天前
多 Agent 架构到底怎么选?从 Claude Agent Teams、Cognition/Devin 到工程落地原则
前端·人工智能·后端