CSS中理解兄弟选择器:完整指南

583 阅读8分钟

CSS选择器中的元素选择有时比通常更棘手。某些情况涉及到进行复杂的逻辑选择,例如针对直接子元素、立即兄弟元素或任何兄弟元素来解决特定布局问题。

幸运的是,一组名为CSS组合器的运算符使得这些复杂的选择变得轻松。本文重点介绍CSS兄弟组合器,它们根据元素在源顺序中相对于彼此的位置来选择元素。

到本文结束时,您将对CSS兄弟组合器及其用法和前端Web开发中的实际应用有一个清晰的了解。我们将通过几个CodePen示例来演示这些概念,因此随着我们的开始,你可以查看集合

什么是CSS兄弟组合器?

兄弟组合器使您能够选择位于给定HTML元素之后的HTML元素。请注意,仅当它们具有相同的父元素时,两个或多个HTML元素才被称为同级。

有两种类型的同级选择器,它们具有相似的功能但可能具有不同的用例。让我们一一查看它们并附带示例。

相邻兄弟组合器

相邻兄弟选择器目标就是紧接在给定HTML元素旁边的元素。加号+用于在CSS中表示相邻兄弟选择:

.first + .next { /* <-- 选择条件的逻辑 */
  /* 应用于相邻兄弟的样式 */
}

以下是相邻兄弟组合器如何在CSS中选择兄弟元素:

See the Pen Adjacent Sibling Combinator in CSS by Rahul C (@_rahul)
on CodePen

一旦添加了选择条件的逻辑,下一步就是向目标元素或元素添加适当的CSS样式属性。上面的示例显示了相邻兄弟选择器的示例,它定位在.first之后紧随其后的.next类。

请注意,仅.first旁边紧接的.next元素被选择,而其其他出现则被忽略。此行为演示了关于元素选择涉及的相邻兄弟组合器的专属性质。

通用兄弟组合器

CSS中的通用兄弟选择器使您能够选择满足指定标准的任何同级元素。这在应用样式于跟随特定HTML元素的多个元素时非常有用,无论它们的直接顺序如何。

波浪号~在CSS中表示通用兄弟选择逻辑。请考虑以下示例,以观察其与前面讨论的相邻兄弟组合器之间的对比:

.first ~ .next {
  /* 应用于通用同级别的样式 */
}

将下表中的结果与我们之前看到的相邻兄弟组合器的示例进行比较:

See the Pen General Sibling Combinator in CSS (~) by Rahul C (@_rahul)
on CodePen

上面的示例清楚地显示了选择给定HTML元素之后发生的任何兄弟选项,这展示了通用兄弟组合器的包容性选择行为。

CSS中通用和相邻兄弟选择的区别

这两个组合器之间的唯一根本区别在于它们的选择方法,这最终决定了它们的功能和应用。

相邻兄弟组合器在其选择方面是排他性的,它严格寻找相匹配特定标准的紧邻的邻居元素。

另一方面,通用兄弟组合器则更具包容性,选择满足特定标准的每个同级元素。

CSS兄弟组合器的应用用例

相邻兄弟组合器具有比通用兄弟组合器更广泛的实际应用。以下各段展示了其中一些用例,并演示了它们在实际场景中的工作方式。

如果可能的话,我还将尝试在某些情况下使用通用兄弟组合器。

还请注意,根据问题的上下文,可能还会有其他用例。如果我有任何遗漏,请在评论中提及其他示例。

改善间距

在排版和间距方面,可能会出现不需要最后一个元素的下边距的情况。由于现代CSS伪类,例如:not:last-child,因此可以轻松忽略最后一个子元素的间距或任何给定的属性:

p:not(:last-child) {
  margin-bottom: 1.5em;
}

但是,如果您尝试应用具有不同底部间距的实用程序类别来样式化使用上述CSS样式的任何元素,则它将无法正常工作。

这是因为这两个伪类比CSS实用程序类别的平凡旧类别具有更高的特殊性。以下是一个示例,让您密切关注该问题:

See the Pen The specificity problem w/ :not(:last-child) by Rahul C (@_rahul

为了解决此问题,我们可以使用CSS相邻兄弟组合器来降低特殊性。通过这种方法,我们可以轻松应用具有边距变化的实用程序类:

See the Pen Preventing :not(:last-child) from snipping last paragraph margin by Rahul C (@_rahul

与这种微调相关的其他用例也可以使用相似的方法来解决。这种操作也可以用于调整内联间距。这种调整的理想用例可能是导航菜单,我们希望修剪或忽略最后一个列表项的右边距:

.inline-nav li + li {
  margin-left: 1em;
}

以下是示例:

See the Pen Preventing :not(:last-child) from snipping last list-item margin by Rahul C (@_rahul

改进内容对齐

考虑一种情况,我们有一些网站标题变体,其中包含导航元素和不包含导航元素的。通过将内容均匀对齐以使它们之间具有相同的间距来使用Flexbox可以轻松实现这样的组件。例如,鉴于以下HTML:

<header class="header">
  <div class="logo">Logo</div>
  <form class="search"><input type="search" placeholder="Search..."></form>
  ...
</header><!-- .header -->

我们的CSS可能如下所示:

.header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5em;
}

现在,另一种具有导航菜单的变体粘贴在左侧并忽略Flexbox内容对齐可以使用相邻兄弟组合器实现:

.nav + .search {
  margin-left: auto;
}

在下面的示例中查看所有三个标题布局变种的情况,无需编写单独的类或调整基于位置和转换的属性:

See the Pen Flexible Header navigation with CSS Sibling Combinators by Rahul C (@_rahul

考虑遵循适用于移动设备的响应式菜单方法,将这些菜单做成响应式布局后再实现。

切换显示

通过在元素显示状态之间添加基于事件的切换,可以使设计更加交互和用户友好。当要切换的元素是目标的同级元素时,相邻兄弟组合器可能非常有用。

一个简单的例子可以是在给定目标上悬停或聚焦时,在目标之外显示幽灵元素。通常使用::after::before伪元素来解决此类问题。

如果需要根据目标元素上的事件切换外部同级元素的样式,此技术可以实现此目的:

button + p {
  display: none;
}

button:hover + p {
  display: block;
}

在下面的CodePen中悬停在该元素上,以查看悬停事件如何切换幽灵元素的显示:

See the Pen Ghost element toggline w/ CSS Sibling Combinator by Rahul C (@_rahul

显示切换是前端中常见的特性。使用此技术来尝试更好的解决方案,使其具有良好的灵活性、透明度或其他样式,以便更好地解决您的布局问题。

模拟基于单击的切换

我们可以使用臭名昭着的复选框方法 来模拟基于单击的切换。不建议在专业环境中使用它,但是值得学习-这是人们几年前在处理小任务时使用的方法。

这种技术的实质在于将复选框输入设置为事件目标,使用:checked伪类跟踪其状态,然后与其状态一起为复选框的同级元素分配样式:

#toggle-sibling + p,
#toggle-general-sibling ~ p {
  display: none;
}

#toggle-sibling:checked + p,
#toggle-general-sibling:checked ~ p {
  display: block;
}

与演示进行交互,以了解其实际应用:

See the Pen Toggling display w/ Sibling and General Sibling Selectors by Rahul C (@_rahul

查看完整的CodePen演示,尝试选中和取消选中复选框输入以注意差异。通过更改事件目标的外观,即复选框输入,我们可以极大地优化这种仅使用CSS的解决方案的美观程度。

实施响应导航

将上面的用例进一步扩展,让我们通过遵循移动优先的方法为传统的网站标题区域创建响应导航。

在不依赖于JavaScript的情况下创建适用于移动设备的导航菜单有点棘手。我们的解决方法使用CSS通用兄弟组合器和复选框hack来处理具有一些杂乱标记的导航菜单:

<header class="header">
  <div class="logo">Logo</div>

  <!-- 复选框hack/用于菜单的切换按钮 -->
  <input class="nav-button" type="checkbox" id="menu">

  <!-- 布局混乱/事件目标周围的其他元素 -->
  <div class="stuff-that-sticks-to-logo">...</div>

  <nav class="nav">
    <ul>
      <li>...</li>
      <li>...</li>
    </ul>
  </nav><!-- .nav -->
</header><!-- .header -->

我假设此时您已经了解了,如果在布局中没有事件目标周围的其他元素-即复选框输入,则使用相邻同级组合器将足以满足需求。

这里需要使用复选框hack来模拟在移动视图中的基于单击的元素切换。如前所述,有了来自:checked伪类的提示,我们可以轻松地