:where() 伪类

零权重选择器,易于覆盖的默认样式

什么是 :where() 伪类?

:where() 伪类的功能与 :is() 类似,都可以简化选择器列表。 但它有一个独特的特性:零权重(specificity = 0)

这意味着 :where() 本身不会增加选择器的优先级,使得样式更容易被覆盖。 这对于创建可覆盖的默认样式、重置样式库等场景非常有用。

  • 零权重 - 不增加选择器优先级
  • 易于覆盖 - 适合默认样式和基础样式库
  • 简化代码 - 与 :is() 一样可以合并选择器
  • 灵活控制 - 在需要低优先级时使用

基础语法

:where() 的语法与 :is() 完全相同,但优先级计算规则不同。

/* 基础语法 */
:where(selector1, selector2, selector3) {
  /* 样式规则 */
}

/* 在复杂选择器中使用 */
:where(.header, .sidebar, .footer) a {
  /* 匹配 .header a, .sidebar a, .footer a */
}

/* 与 :is() 的语法对比 */
:is(.header, .sidebar) a { }    /* 权重: (0,1,1) */
:where(.header, .sidebar) a { } /* 权重: (0,0,1) - 零权重! */
🎯 零权重特性

:where() 的优先级始终为 0,无论其参数列表中包含什么选择器。 这与 :is() 取最高权重的规则完全不同。

/* :where() 的权重始终为 0 */
:where(#id, .class, div) { }  /* 权重: (0,0,0) - 零权重! */
:where(.class, div) { }       /* 权重: (0,0,0) - 零权重! */

/* 对比 :is() 的权重计算 */
:is(#id, .class, div) { }     /* 权重: (1,0,0) - 取最高 */
:is(.class, div) { }          /* 权重: (0,1,0) - 取最高 */
💡 与 :is() 的区别

:is() - 优先级取参数中的最高值,适合需要保持优先级的场景
:where() - 优先级始终为 0,适合需要易于覆盖的默认样式

:is() vs :where() 权重对比

示例 1: 基础权重差异

效果预览
使用 :is(.highlight) - 蓝色
权重: (0,1,1) = 11
:is(.highlight) + .override - 黄色胜出
:is() 权重 (0,1,1) < .override 权重 (0,1,0) + 后定义
使用 :where(.highlight) - 绿色
权重: (0,0,0) = 0
:where(.highlight) + .override - 黄色轻松覆盖
:where() 权重 (0,0,0) < .override 权重 (0,1,0) ✓
/* 使用 :is() - 权重: (0,1,1) = 11 */
:is(.highlight) {
  background: lightblue;
  color: darkblue;
}

/* 使用 :where() - 权重: (0,0,0) = 0 */
:where(.highlight) {
  background: lightgreen;
  color: darkgreen;
}

/* 简单的类选择器 - 权重: (0,1,0) = 10 */
.override {
  background: lightyellow;
  color: darkorange;
}

/* 结果:
   - :is(.highlight) 需要更高权重才能覆盖
   - :where(.highlight) 很容易被 .override 覆盖 ✓ */

示例 2: 覆盖难易程度对比

效果预览

使用 :is()

默认卡片样式
权重: (0,1,1)
自定义样式(需要更高权重)
需要 .card.custom 才能覆盖

使用 :where()

默认卡片样式
权重: (0,0,0)
自定义样式(轻松覆盖)
只需 .custom 就能覆盖 ✓
/* 左侧:使用 :is() - 权重 (0,1,1) */
:is(.card, .panel) {
  background: lightblue;
  color: darkblue;
}

/* 简单类无法覆盖 ❌ */
.custom {
  background: lightyellow; /* 不生效 */
}

/* 需要更高权重 */
.card.custom {
  background: lightyellow; /* 生效 ✓ */
}

/* 右侧:使用 :where() - 权重 (0,0,0) */
:where(.card, .panel) {
  background: lightgreen;
  color: darkgreen;
}

/* 简单类就能覆盖 ✓ */
.custom {
  background: lightyellow; /* 生效 ✓ */
}

示例 3: 权重计算详细对比

权重计算表
选择器 权重 说明
:is(.a, .b) (0,1,0) 取最高权重
:where(.a, .b) (0,0,0) 零权重
:is(#id, .class) (1,0,0) 取 ID 的权重
:where(#id, .class) (0,0,0) 仍然是零权重
div :is(.a, .b) (0,1,1) div(1) + :is()最高权重(10)
div :where(.a, .b) (0,0,1) div(1) + :where()(0)
/* :is() 取参数中的最高权重 */
:is(.a, .b)        /* (0,1,0) */
:is(#id, .class)   /* (1,0,0) - 取 ID */
div :is(.a, .b)    /* (0,1,1) */

/* :where() 始终为零权重 */
:where(.a, .b)     /* (0,0,0) */
:where(#id, .class) /* (0,0,0) - 仍然是 0! */
div :where(.a, .b) /* (0,0,1) - 只有 div */

/* 关键区别:
   :is() 会影响整体权重
   :where() 不会影响整体权重 */

零权重应用场景

场景 1: 可覆盖的默认样式

效果预览
链接按钮 主要链接

💡 默认样式使用 :where(),自定义样式只需简单类名即可覆盖

/* 使用 :where() 设置默认样式 - 权重 (0,0,0) */
:where(button, .btn) {
  padding: 10px 20px;
  border: 2px solid #ccc;
  background: #f5f5f5;
  color: #333;
  cursor: pointer;
}

/* 简单的类就能覆盖 - 权重 (0,1,0) */
.primary {
  background: green;
  color: white;
  border-color: green;
}

.danger {
  background: red;
  color: white;
  border-color: red;
}

/* 优势:
   - 默认样式不会干扰自定义样式
   - 不需要使用 !important
   - 不需要提高选择器权重 */

场景 2: 重置样式库

效果预览 - CSS 重置样式
重置后的默认样式:

标题没有默认边距

段落没有默认边距

  • 列表没有默认样式
  • 没有项目符号
自定义样式轻松覆盖:

文章标题

这是文章的段落内容,有自定义的边距和颜色。

  • 列表项 1
  • 列表项 2
  • 列表项 3

💡 重置样式使用 :where(),项目样式不需要高权重就能覆盖

/* reset.css - 使用 :where() 创建重置样式 */
:where(h1, h2, h3, h4, h5, h6) {
  margin: 0;
  padding: 0;
  font-weight: 600;
}

:where(p, ul, ol) {
  margin: 0;
  padding: 0;
}

:where(ul, ol) {
  list-style: none;
}

/* 项目样式 - 简单选择器就能覆盖 */
.article h2 {
  margin: 20px 0 10px;  /* 轻松覆盖 ✓ */
  color: blue;
}

.article p {
  margin: 15px 0;       /* 轻松覆盖 ✓ */
}

.article ul {
  list-style: disc;     /* 轻松覆盖 ✓ */
  padding-left: 20px;
}

/* 如果不用 :where(),需要这样覆盖:
   .article h2 { } 无法覆盖 h1, h2, h3, h4, h5, h6 { }
   需要更高权重或 !important */

场景 3: 组件库默认样式

效果预览 - 表单组件库

💡 组件库提供默认样式,用户可以轻松自定义而不需要高权重选择器

/* component-library.css - 使用 :where() */
:where(input, textarea, select) {
  width: 100%;
  padding: 8px 12px;
  border: 1px solid #ccc;
  border-radius: 4px;
  font-size: 1rem;
}

:where(input, textarea, select):focus {
  border-color: blue;
}

/* 用户的项目样式 - 简单类名即可覆盖 */
.custom-input {
  border: 2px solid green;  /* 轻松覆盖 ✓ */
  border-radius: 8px;
  padding: 12px 16px;
}

.error-input {
  border: 2px solid red;    /* 轻松覆盖 ✓ */
  background: #fee;
}

/* 优势:
   - 组件库不会强制样式
   - 用户不需要 !important
   - 保持样式的可维护性 */
✅ 使用 :where() 的最佳实践
  • 重置样式:创建易于覆盖的 CSS 重置
  • 组件库:提供默认样式但不强制使用
  • 工具类:创建低优先级的实用工具类
  • 主题样式:设置可被轻松自定义的主题
  • 避免冲突:减少样式优先级冲突
💡 何时使用 :where() vs :is()

使用 :where() 当:

  • 创建默认样式或重置样式
  • 希望样式容易被覆盖
  • 构建组件库或框架
  • 避免优先级冲突

使用 :is() 当:

  • 简化选择器列表
  • 需要保持正常的优先级
  • 不关心覆盖难易程度
  • 需要与其他选择器竞争优先级

浏览器兼容性

:where() 伪类在现代浏览器中得到了广泛支持:

浏览器 支持版本 状态
Chrome / Edge 88+
Firefox 78+
Safari 14+
Opera 74+
💡 兼容性说明

:where():is() 在同一时期获得浏览器支持。 如果需要支持旧版浏览器,可以使用传统的选择器列表作为降级方案。

查看详细兼容性数据 →