SitePoint’s Guide to the :has() Selector in CSS

In this excerpt from Unleashing the Power of CSS, we delve into the CSS :has() selector. Regarded as “the parent selector,” the :has() pseudo-class offers more than just styling an element’s ancestor. With support in Safari 15.4+ and Chromium 105+ (and behind a flag in Firefox), it’s an opportune moment to become acquainted with :has() and its use cases.

As a pseudo-class, the core functionality of :has() is to style the element it’s attached to, also known as the “target” element. This is similar to other pseudo-classes like :hover or :active, where a:hover is intended for styling an element in an active state. However, :has() also shares similarities with :is(), :where(), and :not(), as it accepts a list of relative selectors within its parentheses. This allows :has() to create intricate criteria for testing, making it a highly potent selector.

To comprehend how :has() operates, let’s consider an example of its application. In the following selector, we are testing if an

element has an element as a child:

“`html
article:has(img) {}
“`

A possible outcome of this selector is depicted in the image below. Three article elements are displayed, two with images and both having a palegreen background and distinct padding compared to the one without an image. This selector will apply as long as an element exists anywhere within the

element, whether as a direct child or as a descendant of other nested elements.

If we want the rule to only apply when the element is a direct (un-nested) child of the

element, we can include the child combinator:

“`html
article:has(> img) {}
“`

The result of this modification is shown in the image below. The same three cards are displayed, but this time, only the one where the image is a direct child of the

element has the palegreen background and padding.

In both selectors, the styles we define are applied to the target element, which is the

. Hence, :has() is often referred to as the “parent” selector since if certain elements exist in a certain way, their “parent” receives the assigned styles.

Note: The :has() pseudo-class itself does not add any specificity weight to the selector. Like :is() and :not(), the specificity of :has() is equal to the highest specificity selector in the selector list. For example, :has(#id, p, .class) will have the specificity granted to an id. For a refresher on specificity, review the section on specificity in CSS Master, 3rd Edition.

We can also select a target element if it’s followed by a specific sibling element using the adjacent sibling combinator (+). In the following example, we select an

element only if it’s directly followed by an

:

“`html
h1:has(+ h2) {}
“`

In the image below, two

elements are displayed. In the first one, because the

is followed by an

, the

has a palegreen background applied to it.

Using the general sibling combinator (~), we can check if a specific element is a sibling anywhere following the target. Here, we’re checking if there’s a

element somewhere as a sibling of the

Leave a Reply