The CSS :has() selector is way more than a “Parent Selector”

Safari Technology Preview 137 just dropped, with unflagged support for CSS :has(). Often dubbed “the parent selector”, CSS :has() is way more than that …

~

# CSS :has()?

As per selectors-4 specification:

The :has() CSS pseudo-class represents an element if any of the selectors passed as parameters match at least one element.

This selector is dubbed “the parent selector”, as the default cases indeed allow you to select a parent element that has certain children.

/* Matches <a> elements that contain an <img> child */
a:has(img) { … }

/* Matches <a> elements that directly contain an <img> child */
a:has(> img) { … }

/* Matches <section> elements that don’t contain any heading elements: */
section:not(:has(h1, h2, h3, h4, h5, h6))

Cool!

~

# More than a parent selector

The :has() selector is way more than that just a parent selector though. As Adrian Bece shared in his post on Smashing Magazine:

/*  Matches <figure> elements that have a <figcaption> as a child element */
figure:has(figcaption) { … }

/* Matches <img> elements that is a child of a <figure> that contains a <figcaption> child element */
figure:has(figcaption) img { … }

Here’s a pen:

See the Pen The CSS :has() selector is way more than a “Parent Selector” by Bramus (@bramus)on CodePen.

In browsers that support :has() you should see a red dashed border around the top image.

Here’s another example, from the spec:

/* Matches <h1> elements only if they have a <p> element directly following them */
h1:has(+ p) { … }

Yes, that one also works because the :has() relational pseudo-class selector accepts a <forgiving-relative-selector-list> as an argument. That’s is a list of <relative-selector>s which can contain any of the combinators we already know: +, ~, >, …

~

# Other peculiar traits

Just like CSS :is(), CSS :has() has these specific traits:

  1. The selector list of :has() is forgiving
  2. The specificity of :has() is that of its most specific argument

Hit the post on CSS :is() for more info on this.

~

# Browser Support

💡 Although this post was originally published in December 2021, the section below is constantly being updated. Last update: June 1, 2022.

This table below shows an up-to-date list of browser support:

Chromium (Blink)

🧪 Experimental support available in Chromium 103. To enable it, flip the “Experimental Web Platform Features” flag through chrome://flags/.

On track to ship with Chromium 105.

Firefox (Gecko)

🚫 No support

Safari (WebKit)

🚀 Available in Safari 15.4 and up.

Experimental support first appeared in Safari Technology Preview 137.

The pen embedded below will indicate if the browser you are currently using supports CSS :has() or not:

See the Pen
CSS :has Selector Support test
by Bramus (@bramus)
on CodePen.

To stay up-to-date regarding browser support, you can follow these tracking issues:

~

# Spread the word

To help spread the contents of this post, feel free to retweet its announcement tweet:

~

🔥 Like what you see? Want to stay in the loop? Here's how:

Published by Bramus!

Bramus is a frontend web developer from Belgium, working as a Chrome Developer Relations Engineer at Google. From the moment he discovered view-source at the age of 14 (way back in 1997), he fell in love with the web and has been tinkering with it ever since (more …)

Unless noted otherwise, the contents of this post are licensed under the Creative Commons Attribution 4.0 License and code samples are licensed under the MIT License

Join the Conversation

12 Comments

  1. css:has() – this is the thing I am second-most excited about in browserland. #1 being container queries

    Thanks for the detailed write-up. Shared with my colleagues 🙂

Leave a comment

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.