【H5 前端开发笔记】第 21 期:CSS 选择器 (6) —— 兄弟选择器、否定伪类、选择器性能 详解
这一期把关系型选择器的最后一块拼图补上:兄弟关系,再加上非常实用的否定伪类 :not(),最后聊聊选择器性能的真实情况(2026 年视角)。
一、兄弟选择器(Sibling Combinators)核心对比
| 符号 | 名称 | 写法示例 | 匹配规则 | 方向 | 典型场景 | 特异性影响 |
|---|---|---|---|---|---|---|
+ | 相邻兄弟选择器 | h2 + p | 紧挨着前面的 h2 的第一个 p 兄弟 | 向后 | 标题后第一段去掉上边距 | 无额外 |
~ | 通用兄弟选择器 | h2 ~ p | h2 后面所有 p 兄弟(不限紧邻) | 向后 | 标题后所有段落统一缩进/样式 | 无额外 |
| 无 | (没有前兄弟选择器) | — | CSS 目前无法选择前面的兄弟 | — | — | — |
关键一句话:CSS 只能“向后看兄弟”,不能“向前看”。
二、否定伪类 :not()
:not() 是逻辑否定,括号里写一个或多个选择器列表(CSS Selectors Level 4 后支持多参数,现代浏览器已全部支持)。
/* 旧写法(仍有效,但权重较高) */
li:not(.active):not(.disabled) { opacity: 0.6; }
/* 新写法(2022年后主流浏览器支持,权重更合理) */
li:not(.active, .disabled) { opacity: 0.6; }
/* 常见组合 */
button:not(:disabled) { cursor: pointer; }
a:not([href^="http"]) { color: inherit; } /* 非外部链接 */
div:not(:empty) { min-height: 1em; } /* 非空 div */
p:not(:first-child) { margin-top: 1.5em; } /* 排除第一个段落的上边距 */
权重(Specificity)重要变化(面试常考):
:not()本身不增加特异性- 但括号里的选择器会正常计入特异性
- 多参数列表时,取最高那个选择器的权重(而非累加)
/* 权重都是 0,0,1 */
a:not(.external) /* a (0,0,1) */
a:not(.external, .internal) /* 仍然 0,0,1(取最高) */
/* 旧写法权重更高 */
a:not(.external):not(.internal) /* 0,0,2 */
三、实战代码示例(建议敲一遍)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>兄弟 + :not 演示</title>
<style>
body { font-family: system-ui; max-width: 800px; margin: 3rem auto; line-height: 1.6; }
/* 1. 标题后紧邻的第一段 → 去掉上边距 */
h2 + p {
margin-top: 0;
font-size: 1.1em;
}
/* 2. 标题后面所有段落 → 加左边框 + 缩进 */
h2 ~ p {
padding-left: 1.2rem;
border-left: 4px solid #4caf50;
margin: 1em 0;
}
/* 3. 排除第一个段落的上边距(两种常见写法) */
section p:not(:first-child) {
margin-top: 1.5em;
}
/* 4. 导航:非当前项变淡 */
nav a:not(.current) {
opacity: 0.6;
font-weight: normal;
}
nav a.current {
color: #d32f2f;
font-weight: bold;
}
/* 5. 列表:非空项 + 不是最后一个加下边框 */
.features li:not(:empty):not(:last-child) {
border-bottom: 1px dashed #ccc;
padding-bottom: 0.8em;
margin-bottom: 0.8em;
}
/* 6. 文章中:图片后面紧跟的说明文字特殊样式 */
figure + figcaption {
font-style: italic;
color: #555;
text-align: center;
font-size: 0.95em;
margin-top: 0.4em;
}
/* 7. 排除外部链接的小图标 */
a[href]:not([href^="http"]):not([href^="https"]):not([href^="/"])::after {
content: " ↗";
color: #888;
font-size: 0.8em;
}
</style>
</head>
<body>
<h1>CSS 兄弟 & :not 实战</h1>
<section>
<h2>这是标题</h2>
<p>紧挨着标题的第一段(+ 选择器生效,去掉上边距)</p>
<p>这是第二段(~ 选择器生效,有绿色左边框)</p>
<p>第三段同样有左边框</p>
</section>
<section>
<h2>另一个标题</h2>
<p>段落1(有上边距,因为不是 section 第一个 p)</p>
<p>段落2</p>
</section>
<nav>
<a href="#home" class="current">首页</a> |
<a href="#about">关于</a> |
<a href="#contact">联系</a>
</nav>
<ul class="features">
<li>特性一</li>
<li></li> <!-- 空 li 不显示下边框 -->
<li>特性三</li>
<li>特性四(最后一个,无下边框)</li>
</ul>
<figure>
<img src="https://picsum.photos/600/300?random=1" alt="示例图" width="600">
<figcaption>这是一张随机图片的说明文字(figure + figcaption 生效)</figcaption>
</figure>
<p><a href="/internal">内部链接</a> 和 <a href="https://external.com">外部链接</a></p>
</body>
</html>
四、选择器性能(2025-2026 真实情况总结)
现代浏览器(Blink、WebKit、Gecko)对选择器性能的优化已经非常成熟,绝大多数场景下“选择器性能”已经不是瓶颈。
| 排名(由快到慢,大致) | 选择器类型示例 | 2026 年相对耗时 | 建议 |
|---|---|---|---|
| 最快 | ID #header | ★★★★★ | 首选(但不要滥用) |
| 极快 | 单 class .btn | ★★★★☆ | 日常主力 |
| 很快 | 标签 button、属性 [type="button"] | ★★★★ | 常用 |
| 快 | 子选择器 nav > a、相邻 h2 + p | ★★★★ | 推荐 |
| 稍慢 | 后代选择器 article p | ★★★ | 常用但别太深 |
| 更慢 | 通用兄弟 h2 ~ p | ★★★ | 适度使用 |
| 明显慢 | :nth-child(复杂公式)、:not(复杂) | ★★ | 控制数量 |
| 最慢(避免深层) | 超深后代 + 通配 * | ★ | 尽量避免 |
2026 年共识要点:
- 真正影响大的是“选择器数量” × “DOM 元素数量” × “重排/重绘频率”,而非单个选择器的微秒级差距。
- 避免从右往左想:写
.container .list .item而不是.item(但现代引擎已优化很多)。 - :not() 现在很安全:只要里面不是超级复杂选择器,性能影响已很小。
- 兄弟选择器 + / ~ 性能不错:远好于深层后代。
- 真正要优化的优先级顺序:
- 减少样式规则总量
- 避免在动画/滚动时触发大量重计算的伪类
- 用 class 而非复杂结构伪类做状态切换
- 关键渲染路径(LCP)相关的元素尽量用 ID 或单 class
下一期预告:伪类(下)—— 交互 & 表单 & 链接状态(:hover / :focus-visible / :checked / :required / :valid / :link / :visited …)
有想深入的场景(比如 :not(:has()) 组合性能、面包屑用兄弟选择器等)欢迎留言~
祝大家 CSS 选择器写得又准又快!⚡