Chrome 86–104 完全忽略 :is() 和 :where(),整条规则被跳过且无提示;必须双写降级:先写兼容选择器(如 .btn, .cta),再写 :is() 版本覆盖,顺序不可颠倒。

Chrome 86–104 里 :is() 和 :where() 直接被忽略
Chrome 86 到 104(含)不支持 :is() 和 :where(),遇到这类选择器时浏览器会整条规则跳过,不会报错,也不会降级执行——相当于那行 CSS 不存在。比如 :is(button, [type="submit"]):hover { opacity: 0.8; } 在 Chrome 95 下完全不生效,但开发者工具里也看不到警告。
这不是“没渲染好”,而是解析阶段就被丢弃了。所以不能靠 @supports selector(:is()) 做条件加载:这个 @supports 本身在不支持的浏览器中语法非法,整个块都会被跳过,连 fallback 都没机会执行。
双写 + 手动降级是最稳妥的方案
必须显式写出兼容版本,并放在现代写法之前(CSS 层叠顺序决定谁生效):
-
.btn, .cta, .link { color: blue; }—— 老浏览器走这条 -
:is(.btn, .cta, .link) { color: blue; }—— Chrome 105+、Firefox 103+、Safari 15.4+ 走这条,覆盖前一条(权重一致时后出现者胜)
注意顺序不能反,否则老浏览器会用空规则覆盖掉真实样式。对于 :where(),同样要双写,但得换策略::where() 的核心价值是权重为 0,而手写逗号列表权重不为 0,所以不能简单双写。真要用 :where() 的零权重语义,只能放弃它,改用类名控制或 JS 注入低权样式。
别信 PostCSS 自动展开插件能兜底
某些 PostCSS 插件(如 postcss-is-pseudo-class)声称能将 :is() 编译成逗号分隔列表,但它只处理顶层 :is(),对嵌套结构(如 :is(.a, .b) > :is(span, em))或含伪类的写法(如 :is(:hover, :focus))大概率失效,且无法还原 :where() 的零权重特性。
更关键的是:这些插件通常不识别你项目中是否混用了 :where() 与 :is(),也不会帮你判断权重冲突。例如你写了 :is(.x, #y) span,插件展开成 .x span, #y span 是对的;但如果你本意是靠 :where() 降权,插件却把它也展开了,反而破坏原意。
Vue/React scoped 场景下 :where() 降权失效怎么办?
在 中用 :where(.el-button) 是为了穿透作用域,但 Chrome 86–104 不认 :where(),结果样式压根不应用。此时不能指望框架自动 fallback,必须手动处理:
- 把需要穿透的样式提到全局
块里(最直接) - 用属性选择器模拟低权:比如框架给组件加了
data-v-xxx,你可以写[data-v-xxx] .el-button,权重仍是 0-1-1,虽不如:where()的 0-0-0,但比.el-button(0-1-0)更低,多数场景够用 - 避免在 scoped 中依赖
:where()做关键样式重置,尤其是 Ant Design V5 这类重度使用它的 UI 库——它们在 Chrome 86 下本就会崩,得按官方建议关掉降权配置,而不是硬扛
真正难处理的不是语法不支持,而是你误以为 :where() 只是“写法更短”,其实它改变了层叠逻辑;一旦浏览器不支持,你失去的不是便利性,而是整个优先级设计前提。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











