:not() 用于匹配不满足条件的元素,仅支持简单选择器,不支持复合选择器或逗号分隔多个条件;其优先级不变,无法排除子元素匹配的父元素,现代可用 :has() 配合实现,但需注意兼容性与性能。

:not() 选择器的基本用法和常见误区
:not() 是 CSS 中的伪类选择器,用于匹配不满足括号内条件的元素。它本身不复杂,但容易因嵌套、优先级或浏览器兼容性栽跟头。
- 只接受简单选择器(如
.class、#id、[attr]、div),不能写:not(.a .b)或:not(div p),否则整个规则失效(CSS 语法错误) - 多个条件需用逗号分隔,但每个都必须是简单选择器:✅
:not(.disabled):not([hidden]),❌:not(.disabled, [hidden]) - 它不改变权重:
div:not(.active)的优先级等同于div,不是“减去”权重,而是“过滤后匹配”
排除多个 class 或属性的实用写法
实际项目中常要排除几种状态,比如跳过禁用按钮、隐藏项、或带特定 data 属性的节点。
- 排除多个 class:用链式
:not(),不要试图塞进一个括号里button:not(.disabled):not(.loading):not(.sent)
- 排除含某属性但值不确定的元素:
[data-status]表示“存在该属性”,比写死值更灵活a:not([data-external]):not([data-disabled])
- 想排除子元素中的某类?不行 ——
:not()不能带后代选择器,得换思路(见下一条)
想排除子元素匹配的父元素?:not() 不行,得靠 JS 或结构调整
这是高频误解点:div:not(p span) 是非法的,CSS 不允许在 :not() 里写复合选择器。如果你的目标是“选中那些内部不含 span 的 div”,CSS 原生做不到。
- 浏览器至今不支持
:has()的旧版本(如 Chrome - 若可用
:has()(现代 Chrome/Firefox/Edge),可反向写:div:not(:has(span))
—— 注意这不是:not()的能力,而是:has()的配合 - 更稳妥的做法是提前加标记类,比如渲染时给含
span的div加has-span,再用div:not(.has-span)
性能与兼容性:别在复杂 DOM 里滥用 :not()
:not() 看似轻量,但在深层嵌套或动态列表中可能触发重排或降低选择效率。
- 避免长链式否定:
li:not(.a):not(.b):not(.c):not(.d):not(.e)不如改用正向类.valid单独加在目标元素上 - IE 完全不支持
:not()(除了最简单的:not(selector)形式,且仅 IE9+),若需兼容,得用 JS fallback 或预编译工具(如 PostCSS 插件自动拆解) - 在 Vue/React 组件中,与其依赖 CSS 选择器过滤,不如在数据层筛掉不需要的项,再渲染 —— 更可控,也避免样式穿透问题
真正难的不是写对 :not(),而是判断「这里是否真该用它」。多数时候,提前分类、合理命名、必要时交由 JS 处理,比硬套一个否定选择器更稳。










