1

Selecting previous siblings with CSS :has()

 1 year ago
source link: https://tobiasahlin.com/blog/previous-sibling-css-has/?ref=sidebar
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Selecting previous siblings with CSS :has()

icon.png

One of the more maddening limitations of CSS was for long its inability to select elements based on their children or preceding siblings. This made it impossible to construct CSS selectors that could target previous siblings of an element, but the has:() pseudo-class (along with :not(), :where(), and :is() from Selectors Level 4) has thrown out the old limitations and opened up a new world of possibilities when working with selectors.

As of this writing, :has() is supported by 84.68% of all major browsers (including Chrome and Safari), with Firefox being the notable exception. Experimental support for Firefox launched in July 2022 and can be enabled through the flag layout.css.has-selector.enabled—you can track the progress through this Bugzilla issue. Until that ships, you can use the :has() pseudo-class if you’re not targeting or supporting Firefox, or if you use a polyfill.

Selecting the previous sibling#Copyhttps://tobiasahlin.com/blog/previous-sibling-css-has/#selecting-the-previous-sibling

Imagine that we have a series of elements, like this:

<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="circle"></div>
<div class="box"></div>

…and we want to select and style the element that comes before the circle. The adjacent sibling combinator (+) can select an element that immediately follows another element, and we can combine it with :has() that to select only the .box that’s immediately followed by a .circle (or from the circle’s perspective, its previous sibling):

.box:has(+ .circle) {
  width: 40px;
  height: 40px;
}

You can think of this selector as first 1) selecting all boxes, and then 2) filtering the elements to only those that match the pattern “box + circle”, which will only return the circle’s previous sibling.

Selecting the nth previous sibling#Copyhttps://tobiasahlin.com/blog/previous-sibling-css-has/#selecting-the-nth-previous-sibling

It’s possible to use the adjacent sibling combinator to select any specific element that preceds another. We can select the 2nd previous sibling by using two adjacent sibling combinators:

.box:has(+ * + .circle) {
  width: 40px;
  height: 40px;
}

If you want to, you can equally scope the selector to a class (rather than the catch-all *). In this instance .box siblings:

.box:has(+ .box + .circle) {
  width: 40px;
  height: 40px;
}

This selector can be difficult to grok and parse. It might help to think of it as selecting all boxes (.box), and then filtering those elements so that the remaining .box is the one that matches the pattern “self + box + circle”, which will only be the 2nd previous sibling.

If you want to select the 3rd previous sibling, you can use three adjacent sibling combinators…

.box:has(+ * + * + .circle) {
  width: 40px;
  height: 40px;
}

…and so on and so forth. You can keep on adding adjacent sibling combinators (+) for as long as you want, to select any nth preceding element.

Selecting all preceding siblings#Copyhttps://tobiasahlin.com/blog/previous-sibling-css-has/#selecting-all-preceding-siblings

If you want to select all previous siblings, you can combine the :has() pseudo-class with the general sibling combinator (~), which matches the second element as long as it follows the first, regardless of its position:

.box:has(~ .circle) {
  width: 40px;
  height: 40px;
}

In other words, as long as the .box in this example is followed by a .circle at some point, the .box will be selected and styled.

Selecting all preceding siblings except the most adjacent sibling#Copyhttps://tobiasahlin.com/blog/previous-sibling-css-has/#selecting-all-preceding-siblings-except-the-most-adjacent-sibling

Finally, we can combine the general sibling combinator (~) with the adjacent sibling combinator (+) and select all preceding elements except the most adjacent one:

.box:has(~ * + .circle) {
  width: 40px;
  height: 40px;
}

This selector selects any .box that matches the pattern “self followed by at any point a box + circle”.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK