:is()可合并重复前缀选择器提升可维护性,但语法错误会导致整条规则失效;:where()权重恒为0,仅抑制括号内选择器权重,不降低外部选择器权重;二者适用场景与兼容性不同。

用 :is() 合并多个重复前缀的选择器
当你要给 header h1、header h2、header h3 统一设色,传统写法要列三组逗号分隔选择器,稍一改动就得同步多处。:is() 直接把重复的父级提取出来,内部填入目标元素即可:
header :is(h1, h2, h3) { color: #222; }
它等价于展开后的并集,但可读性和维护性明显提升。注意::is() 内部任意一个选择器语法错误(比如写成 h4.),整个规则会被浏览器完全忽略——这是容错机制,不是 bug。
常见误用场景:
- 在旧版 Safari 或 IE 中直接使用,不加
@supports检测,导致样式丢失 - 嵌套过深时误以为
:is()能“穿透”伪类限制(其实可以,但需注意伪类本身是否合法) - 把
:is(.a, .b, .c)当作性能优化手段——实际解析开销与并集几乎无差别,别指望它提速
用 :where() 避免干扰现有优先级
:where() 和 :is() 表面行为一致,但关键差异在权重:它的优先级恒为 0。这意味着:
.card .title { color: blue; }
.card :where(.title, .subtitle) { color: red; }
第二行不会覆盖第一行,因为 :where() 不提升整体选择器权重——它等价于单纯写 .card .title 和 .card .subtitle,但权重只按 .card 计算。
适用场景:
- 想批量重置某类元素样式,又怕覆盖已有高权重要求(比如第三方 UI 库)
- 构建设计系统基础层,需要“默认但可被轻松覆盖”的规则
- 配合
@layer使用,做低优先级兜底样式
反例:#main :where(button) 的权重仍是 #main 级别(id 权重),不是 0 —— :where() 只消解它自身参数的权重,不抵消外部选择器。
[class*="btn-"] 和 :is() 的分工边界
属性选择器适合类名不规范、有共同子串但非完整单词的场景;:is() 适合已知确切类名或标签名、结构清晰的批量匹配。
比如按钮类名是 btn-primary、btn-danger、btn-small,且你确定它们都带 btn- 前缀:
button[class*="btn-"] { padding: 0.5rem 1rem; }
但这个会误中 my-btn-text;若你只想精确命中那几个标准类,更安全的是:
button:is(.btn-primary, .btn-danger, .btn-small) { padding: 0.5rem 1rem; }
区别在于:
-
[class*="btn-"]匹配的是 class 属性值字符串,不关心语义完整性 -
:is()匹配的是元素是否具有该类名(全词、空格分隔),语义准确 - 前者兼容性更好(IE8+),后者需现代浏览器(Chrome 100+/Safari 15.4+/Firefox 100+)
优先级陷阱:别把 :where() 当“权重清零器”滥用
:where() 确实让参数部分权重归零,但它不能抹掉外部选择器的权重。例如:
#nav :where(.link) { color: orange; }
.nav-link { color: purple; }
看似 :where() 该赢,但实际生效的是 .nav-link —— 因为 #nav :where(.link) 的权重是 id + 0 = id 级(100),而 .nav-link 是 class 级(10)。真正能压倒它的,是 .nav-link !important 或更高权重要素。
容易被忽略的一点::where() 的“零权重”只作用于它括号内的选择器片段,一旦和 id、class 等组合,整体权重仍由组合中最高者决定。它不是全局降权开关,而是局部权重抑制器。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











