网站

CSS 组合器

CSS 组合器 | MDN

引入

HTML 中的元素按照层级结构组织,元素之间有父子关系、后代关系、兄弟关系。

有时候我们需要根据这些关系选中元素,例如”选中容器内的所有段落”、“选中直接子元素”、“选中相邻的兄弟元素”。

CSS 组合器就是用来根据元素之间的关系选中元素的。

正文

定义

定义

CSS 组合器用于组合多个选择器,根据元素在 HTML 文档树中的父子关系后代关系兄弟关系选中元素。

组合器本身不是选择器,而是连接多个选择器的符号,用来表达选择器之间的关系。

CSS 组合器对照表

组合器名称符号语法作用与匹配规则
后代组合器空格A B选中元素 A 内部的所有 B 元素。无论 BA 的直接子元素,还是孙子、曾孙元素,只要嵌套在 A 内部都会被选中。
子代组合器大于号 >A > B仅选中元素 A直接(第一级)子元素 B。不包括更深层级的后代元素。
相邻兄弟组合器加号 +A + B选中紧跟在元素 A 后面的第一个同级元素 B。两者必须拥有相同的父元素,且 B 必须直接挨着 A
通用兄弟组合器波浪号 ~A ~ B选中元素 A 后面的所有同级元素 B。两者必须拥有相同的父元素,但 B 不必紧挨着 A

具体说明

后代组合器(空格)

选中元素内部的所有后代元素,无论嵌套多深。

.container p {
  color: blue;
}

这条规则会选中 .container 内部的所有 <p> 元素,包括直接子元素和更深层级的后代元素。

子代组合器(>

只选中元素的直接子元素,不包括更深层级的后代。

.container > p {
  color: red;
}

这条规则只会选中 .container 的直接子 <p> 元素,嵌套在更深层级的 <p> 不会被选中。

相邻兄弟组合器(+

选中紧跟在某个元素后面的第一个同级元素。

h2 + p {
  font-size: 18px;
}

这条规则会选中紧跟在 <h2> 后面的第一个 <p> 元素,如果 <h2> 后面不是 <p> 或者中间有其他元素,则不会匹配。

通用兄弟组合器(~

选中某个元素后面的所有同级元素。

h2 ~ p {
  color: gray;
}

这条规则会选中 <h2> 后面的所有同级 <p> 元素,不要求紧挨着。

代码示例

为了更直观地理解,假设我们有以下 HTML 结构:

<div class="container">
  <p>我是直接子代段落 1</p>
  <div class="inner">
    <p>我是后代段落 2 (嵌套在 inner 中)</p>
  </div>
  <p>我是直接子代段落 3</p>
  <span>我是一个 span</span>
  <p>我是同级段落 4</p>
</div>

针对上面的 HTML,这四种组合器的效果如下:

1. 后代组合器 (空格)

/* 选中 .container 内的所有 p 元素(段落 1、2、3、4 都会变成红色) */
.container p {
  color: red;
}

2. 子代组合器 ( > )

/* 只选中 .container 的直接子代 p 元素(段落 1、3、4 会变成蓝色,段落 2 不会,因为它是 inner 的子代) */
.container > p {
  color: blue;
}

3. 相邻兄弟组合器 ( + )

/* 选中紧跟在 .inner 后面的同级 p 元素(只有段落 3 会变成绿色) */
.inner + p {
  color: green;
}

4. 通用兄弟组合器 ( ~ )

/* 选中 .inner 后面的所有同级 p 元素(段落 3 和段落 4 都会变成紫色,span 会被跳过) */
.inner ~ p {
  color: purple;
}

例子

文章段落首行缩进

/* 文章中标题后面的第一段不缩进 */
h2 + p {
  text-indent: 0;
}
 
/* 其他段落首行缩进 */
p {
  text-indent: 2em;
}

列表项分隔线

/* 给所有列表项添加顶部边框 */
li {
  border-top: 1px solid #e5e7eb;
}
 
/* 移除第一项的顶部边框 */
li:first-child {
  border-top: none;
}
 
/* 或者使用相邻兄弟组合器 */
li + li {
  border-top: 1px solid #e5e7eb;
}

表单标签和输入框间距

/* 标签后面紧跟的输入框添加顶部间距 */
label + input {
  margin-top: 8px;
}

特点

  • 后代组合器(空格)选中所有后代元素,无论嵌套多深
  • 子代组合器(>)只选中直接子元素,不包括更深层级
  • 相邻兄弟组合器(+)选中紧跟在后面的第一个同级元素
  • 通用兄弟组合器(~)选中后面的所有同级元素
  • 组合器可以连续使用,例如 div > ul > li
  • 组合器可以和其他选择器组合,例如 .box > p.intro
  • 组合器帮助我们根据 HTML 结构选中元素,不需要添加额外的 class

注意事项

  • 后代组合器(空格)可能选中很多元素,注意性能影响
  • 相邻兄弟组合器(+)要求两个元素紧挨着,中间不能有其他元素
  • 通用兄弟组合器(~)只能选中后面的元素,不能选中前面的
  • 子代组合器(>)和后代组合器(空格)很容易混淆,要注意区分
  • 组合器对 HTML 结构敏感,如果结构改变,样式可能失效
  • 过度使用组合器可能导致样式和 HTML 结构耦合过紧,不利于维护

理解

可以把组合器理解为”关系选择工具”。

它让 CSS 能够根据元素在 HTML 树中的位置关系选中元素,而不需要给每个元素都添加 class

例如,“容器内的所有段落”用后代组合器,“容器的直接子段落”用子代组合器,“标题后面的第一段”用相邻兄弟组合器,“标题后面的所有段落”用通用兄弟组合器。

组合器的核心价值是让选择器更精确、代码更简洁,同时减少不必要的 class 使用,让 HTML 结构更清晰。

但也要注意,过度使用组合器会让样式和 HTML 结构耦合过紧,如果 HTML 结构改变,样式可能需要大量修改。

引出

理解了组合器之后,可以继续学习:

也可以学习 CSS 预处理器(例如 Sass、Less),它们提供了更强大的嵌套和组合能力。