Benjamin Read's code garden.

Selecting parents of a nested element with the css :has selector

Published on

This article is about: css

I was playing around with the :has selector recently and noticed it’s got a pretty awesome feature: relative selectors. They’re defined as:

a selector representing an element relative to one or more anchor elements preceded by a combinator. Relative selectors that don’t begin with an explicit combinator have an implied descendant combinator.

That means that :has() is really smart, anything in the brackets behaves like it does in normal CSS.

This really helped me because my DOM structure looks something like:

<div class="element">
  <div>
    <div>
      <div id="element-i-want-to-target">

According to this stackoverflow answer, I would need to write something like:

.element:has(div > div > div#element-i-want-to-target) {}

(This is Drupal by the way, which seems to love nested <div>s even more than React)

The trouble with that is that it didn’t work as I had expected. It never targeted the element correctly, and after playing around I couldn’t get it to respond correctly.

By chance experimentation I came up with this:

.element:has(#element-i-want-to-target) {}

And it worked! Even though the targeted element was 3 <div>s deep, it’s relative to the parent .element, and so :has() evaluated it as I desired.

This makes sense given the MD docs, but it’s still not all that clear, I wish that MDN would have shown the HTML structure along with its examples.

But it makes sense if you think about it: by using :has() you’re scoping your CSS to the parent you’re using it on; anything appearing inside that pseudoselector works just like normal CSS does.

I do love these recent additions to CSS, it’s made it so awesome to work with.

Read more articles about: css

“Wisest are they who know they do not know.”

— Jostein Gaarder