CSS Sibling Selectors: Targeting Elements Relative to Others

CSS provides powerful ways to select elements based on their relationships to other elements in the document tree. While selecting next siblings is straightforward with the + and ~ combinators, selecting previous siblings directly isn’t as readily available. This tutorial explores the available techniques and approaches to achieve this, from leveraging existing combinators to utilizing newer CSS features.

Understanding Sibling Relationships

Before diving into selectors, let’s clarify sibling relationships. Sibling elements share the same parent element. CSS provides ways to target these siblings based on their order.

  • Adjacent Sibling Selector (+): This selects an element that is immediately preceded by another specific element.

    h2 + p {
      font-style: italic;
    }
    

    This styles any <p> element that immediately follows an <h2> element.

  • General Sibling Combinator (~): This selects all sibling elements that follow a specific element, but not necessarily immediately.

    h2 ~ p {
      color: gray;
    }
    

    This styles all <p> elements that are siblings of an <h2> element, regardless of how many elements separate them.

The Challenge of Selecting Previous Siblings

CSS 2.1 doesn’t provide a direct selector for previous siblings. This means we need to employ alternative strategies to achieve the desired styling.

1. Leveraging :hover and General Sibling Combinator (~)

A common use case is to style previous siblings on hover. We can combine the :hover pseudo-class with the general sibling combinator (~) to achieve this effect.

<div class="parent">
  <a href="#">link</a>
  <a href="#">link</a>
  <a href="#">link</a>
  <a href="#">link</a>
  <a href="#">link</a>
</div>
.parent a {
  color: blue;
}

.parent:hover a,
.parent a:hover ~ a {
  color: blue;
}

In this example, when hovering over any link within .parent, all previous links will remain blue (original color), but the hovered link and all subsequent links will also be blue. This is because a:hover ~ a selects all sibling a elements following the hovered one.

2. The :has() Selector (CSS Selectors Level 4)

CSS Selectors Level 4 introduces the :has() pseudo-class, which allows selection based on the presence of other elements. This opens up possibilities for selecting previous siblings.

previous:has(+ next) {
  /* Styles for the previous sibling */
}

previous:has(~ next) {
  /* Styles for a general previous sibling */
}

Here, :has(+ next) will select an element that has an immediately following sibling, while :has(~ next) selects an element that has a sibling following it at any distance. It’s crucial to remember that :has() is relatively new and browser support, while excellent, isn’t universal for older browsers.

Example using :has()

<ul>
  <li>one</li>
  <li>two</li>
  <li>three</li>
  <li class="x">four</li>
  <li>five</li>
</ul>
ul {
  display: flex;
  list-style: none;
}

li {
  padding: 3px;
  margin: 1em;
}

li:has(+ .x) {
  outline: solid blue 3px;
}

li:has(~ .x) {
  background: yellow;
}

.x {
  font-weight: bold;
}

In this example, the li element immediately preceding .x will have a blue outline, and any li element preceding .x will have a yellow background.

Browser Compatibility

Before using any advanced selectors like :has(), always check browser compatibility on websites like CanIUse. This will help you understand which browsers support the feature and whether you need to provide fallbacks for older browsers.

Conclusion

While CSS doesn’t offer a dedicated “previous sibling” selector, you can achieve the desired styling using combinations of existing selectors, pseudo-classes, and the newer :has() selector. Understanding these techniques will give you greater control over your stylesheets and enable you to create more dynamic and visually appealing web pages.

Leave a Reply

Your email address will not be published. Required fields are marked *