:not() 只接受单个简单选择器,不支持逗号分隔或多条件复合选择器;正确写法是嵌套如 li:not(.active):not(.disabled),属性选择器如 li:not([data-status="draft"]) 兼容且需注意匹配规则。

为什么 :not() 不能直接写成 li:not(.active, .disabled)
因为 CSS 规范明确限制::not() 的参数只能是「单个简单选择器」,不支持逗号分隔的多个选择器,也不支持复合选择器(如 .active:hover)。写成 li:not(.active, .disabled) 会直接被浏览器忽略——连报错都不会有,静默失效。
正确做法是把多个排除条件「拆成嵌套 :not()」:
li:not(.active):not(.disabled)
这等价于「既不是 .active,也不是 .disabled」。如果漏掉一层,比如只写 li:not(.active),那 .disabled 项仍会被选中——这点常被忽略。
如何排除带特定属性的 <li>(比如 data-status="draft")
属性选择器完全兼容 :not(),而且写法直观。注意属性值是否需要引号、是否区分大小写:
-
li:not([data-status="draft"])—— 精确匹配字符串值 -
li:not([data-status~="draft"])—— 匹配空格分隔的单词(类似class) -
li:not([data-status^="arch"])—— 排除属性值以arch开头的项(但:not()内部不支持$=或*=这类模糊匹配)
特别提醒::not([hidden]) 和 :not([hidden=""]) 效果不同——前者排除所有含 hidden 属性的元素(无论值是什么),后者只排除显式写成 hidden="" 的。
用 :not() 配合 :nth-child() 跳过开头几项时的常见陷阱
比如想选「从第 3 项开始的所有 <li>」,别写 li:not(:nth-child(-n+2))——语法合法,但可读性差,且容易和 :nth-of-type 混淆。
更稳妥的方式是优先用原生逻辑表达:
li:nth-child(n+3)
但如果必须用 :not()(例如要排除某些带类名的前几项),注意顺序:伪类组合中,:not() 必须放在最后,否则无效:
- ✅
li:nth-child(n+1):not(.skip)—— 先选所有,再排除.skip - ❌
li:not(.skip):nth-child(n+1)—— 浏览器可能按规范解析为「先排除再找序号」,行为不可靠
当 :not() 遇上动态类名(如 Tailwind 的 md:hidden)
Tailwind 生成的响应式类本质是普通类名,:not() 完全能用,但要注意媒体查询上下文:
下面这段代码在桌面端生效,但在移动端不会自动“反转”:
@media (min-width: 768px) {
li:not(.md\:hidden) {
background: #f0f0f0;
}
}
关键点:md:hidden 中的反斜杠是 CSS 类名转义符,必须双写(md\:hidden)才能在 CSS 文件里正确识别;而 JS 动态增删类时,直接操作 "md:hidden" 字符串即可——两边转义规则不一致,容易漏掉一个反斜杠导致样式不生效。
真正容易被忽略的是:CSS 里没有“排除所有响应式隐藏类”的通配写法。你不能写 :not([class*="hidden"]),因为 class 属性值是空格分隔的字符串,*= 匹配会误伤正常类名(比如 highlighted 里也含 hidden)。老老实实列全要排除的类更可靠。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











