后续兄弟选择器
概述
后续兄弟选择器(也称为通用兄弟选择器,General Sibling Combinator)用于选择某个元素之后的所有同级兄弟元素。
语法
元素1 ~ 元素2 {
属性: 值;
}注意: 两个元素之间用波浪号 ~ 分隔,并且要有空格。
基本示例
1. 基本用法
/* 选择 h2 之后的所有同级段落 */
h2 ~ p {
color: red;
}<h2>标题</h2>
<p>这个段落会被选中(红色)</p>
<p>这个段落会被选中(红色)</p>
<div>其他内容</div>
<p>这个段落会被选中(红色)</p>2. 选择特定类型的元素
/* 选择 div 之后的所有同级 p */
div ~ p {
background-color: yellow;
}
/* 选择 li 之后的所有同级 li */
li ~ li {
margin-left: 10px;
}工作原理
后续兄弟选择器的要求:
- 同级关系: 两个元素必须有相同的父元素
- 后续位置: 元素2必须在元素1之后
- 不限数量: 选择所有符合条件的后续元素
图示
父元素
├── 元素1 (h2)
├── 元素2 (p) ✓ 会被选中
├── 元素3 (div) ✗ 不会被选中(不是 p)
├── 元素4 (p) ✓ 会被选中
├── 元素5 (p) ✓ 会被选中
└── 元素6 (span) ✗ 不会被选中(不是 p)与相邻兄弟选择器的区别
相邻兄弟选择器(+)
h2 + p {
/* 只选择紧跟在 h2 之后的第一个 p */
color: red;
}效果: 只选择紧邻的第一个元素
后续兄弟选择器(~)
h2 ~ p {
/* 选择 h2 之后的所有同级 p 元素 */
color: red;
}效果: 选择后面所有的同级元素
对比示例
/* 相邻兄弟选择器 */
.title + p {
color: red; /* 只有紧邻的第一个 p 是红色 */
}
/* 后续兄弟选择器 */
.title ~ p {
color: blue; /* title 后面所有的 p 都是蓝色 */
}<div class="title">标题</div>
<p>第一个段落 - 红色(+) / 蓝色(~)</p>
<p>第二个段落 - 不变色(+) / 蓝色(~)</p>
<div>其他内容</div>
<p>第三个段落 - 不变色(+) / 蓝色(~)</p>权重计算
后续兄弟选择器的权重是各组成部分权重之和:
h2 ~ p {
/* 权重 = 1(h2) + 1(p) = 2 */
color: red;
}
.title ~ .box {
/* 权重 = 10(.title) + 10(.box) = 20 */
color: blue;
}
#header ~ p {
/* 权重 = 100(#header) + 1(p) = 101 */
color: green;
}常见应用场景
1. 列表项样式
/* 除第一个外的所有列表项 */
li ~ li {
border-top: 1px solid #eee;
}<ul>
<li>列表项 1 (无上边框)</li>
<li>列表项 2 (有上边框)</li>
<li>列表项 3 (有上边框)</li>
<li>列表项 4 (有上边框)</li>
</ul>2. 表单控件间距
/* 除第一个外的所有输入框 */
input ~ input {
margin-left: 10px;
}<form>
<input type="text" placeholder="用户名">
<input type="password" placeholder="密码">
<input type="email" placeholder="邮箱">
</form>3. 卡片布局
/* 卡片之间的间距 */
.card ~ .card {
margin-top: 20px;
}4. 导航菜单
/* 除第一个外的所有导航项 */
.nav-item ~ .nav-item::before {
content: "|";
margin: 0 10px;
color: #ccc;
}<nav>
<a href="#" class="nav-item">首页</a>
<a href="#" class="nav-item">产品</a>
<a href="#" class="nav-item">关于</a>
<a href="#" class="nav-item">联系</a>
</nav>5. 标题和内容
/* 标题之后的所有段落 */
h2 ~ p {
color: #666;
line-height: 1.8;
}<article>
<h2>文章标题</h2>
<p>段落1 (会应用样式)</p>
<p>段落2 (会应用样式)</p>
<div>其他内容</div>
<p>段落3 (会应用样式)</p>
</article>6. 图片库
/* 图片之间的间距 */
.gallery img ~ img {
margin-left: 10px;
}7. 标签组
/* 标签之间的间距 */
.tag ~ .tag {
margin-left: 5px;
}<div class="tags">
<span class="tag">HTML</span>
<span class="tag">CSS</span>
<span class="tag">JavaScript</span>
<span class="tag">Vue</span>
</div>8. 按钮组
/* 按钮之间的间距 */
.btn ~ .btn {
margin-left: 10px;
}9. 段落缩进
/* 首段之后的所有段落缩进 */
p ~ p {
text-indent: 2em;
}<article>
<p>第一段不缩进...</p>
<p>这段会缩进...</p>
<p>这段也会缩进...</p>
<p>这段也会缩进...</p>
</article>10. 评论系统
/* 首条评论之后的所有评论 */
.comment ~ .comment {
border-top: 1px solid #eee;
padding-top: 20px;
margin-top: 20px;
}11. 图标和文字
/* 图标之后的文字 */
.icon ~ span {
margin-left: 8px;
}12. 状态指示
/* 当前项之后的所有项 */
.current ~ .item {
opacity: 0.6;
}<ul class="steps">
<li class="item">步骤1 (不透明)</li>
<li class="item current">步骤2 (不透明)</li>
<li class="item">步骤3 (半透明)</li>
<li class="item">步骤4 (半透明)</li>
</ul>高级用法
1. 与伪类配合
/* 选中特定元素之后的所有元素 */
.active ~ li {
background-color: #f9f9f9;
}
/* 焦点元素之后的所有元素 */
input:focus ~ input {
border-color: #3498db;
}2. 与伪元素配合
/* 在后续元素前添加内容 */
h2 ~ p::before {
content: "• ";
color: #3498db;
}3. 多个后续选择器组合
/* 选择特定元素之后的不同类型元素 */
.title ~ h3,
.title ~ h4,
.title ~ p {
color: #666;
}4. 选择不同层级的后续元素
/* 标题之后的所有标题 */
h2 ~ h3,
h2 ~ h4,
h2 ~ h5,
h2 ~ h6 {
margin-top: 20px;
}5. 响应式设计
/* 小屏幕下调整间距 */
@media (max-width: 768px) {
.btn ~ .btn {
margin-left: 5px;
margin-top: 5px;
}
}6. 交互动画
/* 悬停效果 */
.box:hover ~ .item {
transform: translateX(10px);
transition: transform 0.3s ease;
}7. 交替样式
/* 奇偶样式 */
li:nth-child(odd) ~ li:nth-child(even) {
background-color: #f9f9f9;
}
li:nth-child(even) ~ li:nth-child(odd) {
background-color: #fff;
}8. 表格样式
/* 表格行 */
tr ~ tr {
border-top: 1px solid #eee;
}
tr:nth-child(even) ~ tr:nth-child(even) {
background-color: #f8f8f8;
}实战案例
案例1: 步骤进度条
/* 步骤项 */
.step {
display: inline-block;
width: 40px;
height: 40px;
line-height: 40px;
text-align: center;
border: 2px solid #ddd;
border-radius: 50%;
background: #fff;
transition: all 0.3s ease;
}
/* 当前步骤 */
.step.active {
border-color: #3498db;
background: #3498db;
color: white;
}
/* 当前步骤之后的所有步骤 */
.step.active ~ .step {
border-color: #ddd;
opacity: 0.5;
}<div class="steps">
<div class="step completed">1</div>
<div class="step active">2</div>
<div class="step">3</div>
<div class="step">4</div>
<div class="step">5</div>
</div>案例2: 价格表
/* 价格项 */
.price-item {
padding: 20px;
background: #fff;
border-radius: 10px;
margin-bottom: 15px;
}
/* 推荐项 */
.price-item.featured {
border: 2px solid #3498db;
transform: scale(1.05);
}
/* 推荐项之后的所有项 */
.price-item.featured ~ .price-item {
opacity: 0.8;
}案例3: 选项卡
/* 选项卡 */
.tab-item {
padding: 10px 20px;
background: #f5f5f5;
border-radius: 5px 5px 0 0;
cursor: pointer;
}
/* 激活的选项卡 */
.tab-item.active {
background: #fff;
color: #3498db;
}
/* 激活的选项卡之后的所有选项卡 */
.tab-item.active ~ .tab-item {
background: #f5f5f5;
color: #666;
}案例4: 图片画廊
/* 图片容器 */
.gallery-item {
position: relative;
overflow: hidden;
border-radius: 10px;
}
/* 图片之后的遮罩 */
.gallery-item:hover ~ .overlay {
opacity: 1;
}
/* 悬停时的遮罩 */
.gallery-item:hover .overlay {
opacity: 0.7;
}案例5: 对话框
/* 消息 */
.message {
max-width: 70%;
padding: 10px 15px;
border-radius: 10px;
margin-bottom: 15px;
}
/* 发送的消息 */
.message.sent {
background: #3498db;
color: white;
margin-left: auto;
}
/* 接收的消息 */
.message.received {
background: #f1f1f1;
color: #333;
}
/* 发送消息之后的所有消息 */
.message.sent ~ .message.received {
border-top-left-radius: 5px;
}案例6: 新闻列表
/* 新闻项 */
.news-item {
padding: 20px;
border-bottom: 1px solid #eee;
}
/* 重点新闻 */
.news-item.featured {
background: #fff9c4;
}
/* 重点新闻之后的所有新闻 */
.news-item.featured ~ .news-item {
opacity: 0.9;
}案例7: 联系方式
/* 联系项 */
.contact-item {
display: flex;
align-items: center;
padding: 15px 0;
border-bottom: 1px solid #eee;
}
/* 第一项之后的所有项 */
.contact-item ~ .contact-item {
border-top: none;
}
/* 图标之后的文字 */
.contact-item .icon ~ .text {
margin-left: 15px;
}注意事项
1. 必须是同级元素
/* ❌ 不会选中 - 不是同级 */
.parent > .first ~ .second {
/* ... */
}<div class="parent">
<div class="first"></div>
<div class="wrapper">
<div class="second"></div>
</div>
</div>2. 只选择后续元素
h2 ~ p {
/* 只选择 h2 之后的 p,不会选择之前的 */
}<p>不会被选中</p>
<h2>标题</h2>
<p>会被选中</p>
<p>会被选中</p>3. 空格很重要
/* ❌ 错误: 缺少空格 */
div~p {}
/* ✅ 正确: 有空格 */
div ~ p {}4. 性能考虑
/* ❌ 不推荐: 选择器过于复杂,影响性能 */
body > div > div > div ~ p {}
/* ✅ 推荐: 使用类名简化 */
.paragraph {}5. 与其他选择器配合
/* 可以与其他选择器组合使用 */
.container h2 ~ p {
/* ... */
}
.active ~ .item {
/* ... */
}与相邻兄弟选择器的选择
| 场景 | 推荐选择器 | 原因 |
|---|---|---|
| 只需要第一个相邻元素 | + | 更精确,性能更好 |
| 需要所有后续元素 | ~ | 一次性选择所有 |
| 列表分隔线 | ~ | 更简洁 |
| 按钮组间距 | ~ | 统一处理 |
| 特定位置的元素 | + | 更精确 |
性能优化
- 避免过度使用: 只在需要时使用
- 简化选择器: 使用类名代替复杂选择器
- 限制范围: 尽量在特定容器内使用
- 测试性能: 在大型页面中测试性能影响
最佳实践
- 分隔线: 使用后续兄弟选择器添加分隔线
- 间距控制: 统一管理元素之间的间距
- 状态指示: 控制后续元素的状态
- 列表样式: 统一列表项的样式
- 导航菜单: 添加分隔符
- 避免复杂选择器: 保持选择器简洁
- 合理使用: 根据实际需求选择合适的选择器
- 代码可读性: 复杂选择器添加注释
总结
后续兄弟选择器是一种强大的选择器,能够选择某个元素之后的所有同级元素。理解其工作原理和应用场景,能够帮助我们在特定情况下编写更简洁、高效的 CSS 代码。与相邻兄弟选择器配合使用,可以满足各种复杂的选择需求