:not() 伪类

排除特定元素,实现反向选择

什么是 :not() 伪类?

:not() 伪类允许你选择不匹配特定选择器的元素。 它是一个强大的排除工具,可以帮助你精确地选择需要的元素,而无需为每个元素添加额外的类名。

在现代 CSS 中,:not() 已经支持复杂选择器列表,可以同时排除多个条件, 甚至可以链式使用多个 :not() 来实现更复杂的排除逻辑。

  • 反向选择 - 选择不符合条件的元素
  • 减少类名 - 避免为排除的元素添加额外类
  • 支持复杂选择器 - 可以排除复杂的选择器组合
  • 可链式使用 - 多个 :not() 可以组合使用

基础语法

:not() 接受一个或多个选择器作为参数,匹配不符合这些选择器的元素。

/* 基础语法 - 排除单个选择器 */
:not(selector) {
  /* 样式规则 */
}

/* 排除多个选择器(现代语法) */
:not(selector1, selector2, selector3) {
  /* 匹配"不是 selector1、selector2 或 selector3"的元素 */
  /* 等价于:既不是 selector1,也不是 selector2,也不是 selector3 */
}

/* 常见用法示例 */

/* 选择除最后一个外的所有 li */
li:not(:last-child) {
  border-bottom: 1px solid #ccc;
}

/* 选择没有 .active 类的链接 */
a:not(.active) {
  color: gray;
}

/* 选择不是 disabled 的按钮 */
button:not(:disabled) {
  cursor: pointer;
}

/* 排除多个类 */
div:not(.header, .footer, .sidebar) {
  padding: 20px;
}

/* 链式使用 :not() */
input:not([type="submit"]):not([type="button"]) {
  border: 1px solid #ccc;
}
💡 现代语法支持

现代浏览器支持在 :not() 中使用复杂选择器列表。 你可以在一个 :not() 中排除多个选择器,而不需要链式使用多个 :not()

/* 旧语法 - 链式使用(兼容性更好) */
p:not(.intro):not(.summary) { }

/* 新语法 - 一次排除多个(更简洁) */
p:not(.intro, .summary) { }

/* 两者完全等价!都表示"既不是 .intro 也不是 .summary" */

逻辑解释::not(.intro, .summary) 表示"不是(.intro 或 .summary)", 根据德摩根定律,等价于"不是.intro 且 不是.summary"

⚠️ 优先级计算

:not() 本身不增加优先级,但其参数中的选择器会计入优先级。 与 :is() 类似,:not() 的优先级取决于其参数列表中优先级最高的选择器。

/* :not() 的权重取决于参数 */
:not(.class) { }        /* 权重: (0,1,0) */
:not(#id) { }           /* 权重: (1,0,0) */
:not(div) { }           /* 权重: (0,0,1) */
:not(.a, .b, #id) { }   /* 权重: (1,0,0) - 取最高 */

基础排除示例

⚠️ 重要概念:逻辑关系

:not(A, B, C) 表示"不是(A 或 B 或 C)",根据德摩根定律,等价于"不是A 且 不是B 且 不是C"

✓ 会被选中:既不是 A,也不是 B,也不是 C 的元素
✗ 不会被选中:是 A、B 或 C 中任意一个的元素

示例:p:not(.intro, .summary) 只会选中既没有 .intro也没有 .summary 类的 <p> 元素

示例 1: 选择除最后一个外的所有元素

效果预览
  • 列表项 1 - 有底部边框
  • 列表项 2 - 有底部边框
  • 列表项 3 - 有底部边框
  • 列表项 4 - 有底部边框
  • 列表项 5 - 最后一个,没有边框

💡 除了最后一个列表项,其他都有底部边框和间距

/* 为除最后一个外的所有 li 添加边框 */
li:not(:last-child) {
  border-bottom: 2px solid green;
  margin-bottom: 10px;
}

/* 这样可以避免最后一个元素有多余的边框
   比手动为每个元素添加类名更简洁 */

示例 2: 排除特定类的元素

效果预览
普通盒子 1
普通盒子 2
特殊盒子 ⭐
普通盒子 3
普通盒子 4
特殊盒子 ⭐

💡 普通盒子使用蓝色样式,特殊盒子使用黄色样式

/* 为所有不是 .special 的盒子设置蓝色样式 */
.box:not(.special) {
  background: lightblue;
  color: darkblue;
  border-color: blue;
}

/* 特殊盒子单独设置样式 */
.box.special {
  background: lightyellow;
  color: darkorange;
  border-color: orange;
}

/* 优势:不需要为每个普通盒子添加额外的类名 */

示例 3: 排除多个条件

效果预览

💡 排除了 primary、danger、warning 类的按钮都使用默认样式

/* 为所有不是特殊类型的按钮设置默认样式 */
button:not(.primary, .danger, .warning) {
  background: #f5f5f5;
  color: #333;
  border-color: #ccc;
}

button:not(.primary, .danger, .warning):hover {
  background: white;
  border-color: #999;
}

/* 特殊按钮单独设置样式 */
button.primary { background: green; color: white; }
button.danger { background: red; color: white; }
button.warning { background: orange; color: white; }

/* 一次排除多个条件,比链式 :not() 更简洁 */

链式 :not() 示例

多个 :not() 可以链式使用,实现更复杂的排除逻辑。每个 :not() 都会进一步过滤元素。

示例 1: 多个 :not() 组合使用

效果预览
Header 区域 - 蓝色
主内容区域 1 - 绿色 ✓
Sidebar 区域 - 黄色
主内容区域 2 - 绿色 ✓
主内容区域 3 - 绿色 ✓

💡 链式 :not() 排除了 demo-header、demo-footer、demo-sidebar,只有主内容区域显示绿色

/* 链式使用多个 :not() */
.item:not(.demo-header):not(.demo-footer):not(.demo-sidebar) {
  background: lightgreen;
  color: darkgreen;
  border-color: green;
}

/* 等价于现代语法(如果浏览器支持) */
.item:not(.demo-header, .demo-footer, .demo-sidebar) {
  background: lightgreen;
  color: darkgreen;
  border-color: green;
}

/* 每个 :not() 都会进一步过滤元素
   只有同时不是 demo-header、demo-footer、demo-sidebar 的元素才会被选中 */

示例 2: 复杂条件排除

效果预览
激活状态
普通优先级
未激活
高优先级
未激活
普通优先级
(灰色)
激活状态
高优先级
未激活
低优先级
(灰色)
激活状态
普通优先级

💡 既不是激活状态也不是高优先级的卡片显示为灰色

/* 排除激活状态和高优先级的卡片 */
.card:not([data-status="active"]):not([data-priority="high"]) {
  background: #f5f5f5;
  color: #999;
  opacity: 0.6;
}

/* 激活状态的卡片 */
.card[data-status="active"] {
  background: lightgreen;
  color: darkgreen;
}

/* 高优先级的卡片 */
.card[data-priority="high"] {
  background: lightcoral;
  color: darkred;
}

/* 同时满足两个条件的卡片 */
.card[data-status="active"][data-priority="high"] {
  background: lightyellow;
  color: darkorange;
}

/* 链式 :not() 实现"既不是...也不是..."的逻辑 */

示例 3: 结合其他伪类使用

效果预览
  • 第一项 - 蓝色(不可悬停)
  • 中间项 1 - 可悬停变绿
  • 中间项 2 - 可悬停变绿
  • 中间项 3 - 可悬停变绿
  • 中间项 4 - 可悬停变绿
  • 最后一项 - 粉色(不可悬停)

💡 只有中间的列表项在悬停时会变色和移动

/* 只为中间的列表项添加悬停效果 */
li:not(:first-child):not(:last-child):hover {
  background: green;
  color: white;
  transform: translateX(10px);
}

/* 第一项和最后一项有特殊样式 */
li:first-child {
  background: lightblue;
  color: darkblue;
}

li:last-child {
  background: lightpink;
  color: darkred;
}

/* 链式 :not() 结合伪类,实现精确控制 */

表单验证场景

:not() 在表单验证中非常有用,可以轻松选择未填写、未禁用或特定状态的表单元素。

场景 1: 排除已填写的输入框

效果预览

💡 已填写的输入框显示绿色边框,未填写的显示黄色边框

/* 已填写的输入框(不显示占位符) */
input:not(:placeholder-shown) {
  border-color: green;
  background: lightgreen;
}

/* 未填写的输入框(显示占位符) */
input:placeholder-shown {
  border-color: orange;
}

/* :placeholder-shown 伪类在输入框为空时匹配
   :not(:placeholder-shown) 选择已有内容的输入框 */

场景 2: 排除禁用的按钮

效果预览

💡 只有未禁用的按钮可以悬停和点击

/* 只为未禁用的按钮设置交互样式 */
button:not(:disabled) {
  background: green;
  color: white;
  cursor: pointer;
}

button:not(:disabled):hover {
  background: darkgreen;
  transform: translateY(-2px);
}

/* 禁用的按钮 */
button:disabled {
  background: #f5f5f5;
  color: #999;
  cursor: not-allowed;
  opacity: 0.5;
}

/* 避免为禁用按钮添加不必要的交互效果 */

场景 3: 必填字段验证

效果预览

💡 必填字段有效时显示绿色,无效时显示红色;可选字段使用虚线边框

/* 必填字段:已填写且有效 */
input:required:not(:focus):not(:placeholder-shown):valid {
  border-color: green;
  background: lightgreen;
}

/* 必填字段:已填写但无效 */
input:required:not(:focus):not(:placeholder-shown):invalid {
  border-color: red;
  background: lightcoral;
}

/* 可选字段:使用虚线边框 */
input:not(:required) {
  border-style: dashed;
}

/* 多个 :not() 组合:
   - 不在焦点状态
   - 不显示占位符(已填写)
   - 配合 :valid/:invalid 实现实时验证 */

浏览器兼容性

:not() 伪类是 CSS 的基础特性,在所有现代浏览器中都得到了支持:

浏览器 基础支持 复杂选择器列表 状态
Chrome / Edge 1+ 88+
Firefox 1+ 84+
Safari 3.1+ 9+
Opera 9.5+ 74+
💡 兼容性说明

基础 :not() - 只支持简单选择器,所有浏览器都支持
复杂选择器列表 - 支持 :not(selector1, selector2) 语法,需要较新版本

如果需要支持旧版浏览器,可以使用链式 :not() 代替复杂选择器列表:

/* 旧浏览器兼容写法 */
element:not(.a):not(.b):not(.c) { }

/* 现代浏览器简化写法 */
element:not(.a, .b, .c) { }

查看详细兼容性数据 →