search ]

Understanding the CSS :has Property with Examples

The :has pseudo-class in CSS is a powerful selector introduced in CSS Selectors Level 4. This property allows developers to apply styles to an element based on the presence of its descendants or related elements, effectively enabling “parent” selectors, which was a long-requested feature in CSS.

What is the :has Property?

The :has property is a relational pseudo-class that matches elements containing elements that meet certain criteria. It’s particularly useful for styling an element if it contains specific child elements or if certain conditions within its subtree are met.

Syntax

The basic syntax of the :has pseudo-class is:

element:has(selector) {
    /* styles */
}

In this syntax, element represents the parent element, and selector represents the child or descendant elements being checked.

Practical Examples

Here are a few examples.

Example 1: Highlighting a Parent Element Based on a Child Element

Suppose we want to highlight a div element if it contains an img element. Here’s how we can do it:

<div>
    <p>This div contains an image.</p>
    <img src="https://via.placeholder.com/150" alt="Placeholder Image">
</div>
<div>
    <p>This div does not contain an image.</p>
</div>
div:has(img) {
    border: 2px solid green;
    padding: 10px;
}

Example 2: Styling a List Item’s Parent Based on the Child Element

If we want to style a ul element differently when it contains a li element with a specific class, we can use the :has property:

<ul>
    <li>Item 1</li>
    <li class="highlight">Item 2</li>
    <li>Item 3</li>
</ul>
<ul>
    <li>Item A</li>
    <li>Item B</li>
    <li>Item C</li>
</ul>
ul:has(li.highlight) {
    background-color: lightyellow;
    padding: 10px;
}

Example 3: Form Validation Styles

We can also use the :has pseudo-class for form validation. For instance, to style an input element’s parent div if the input is invalid:

<form>
    <div class="form-group">
        <label for="email">Email:</label>
        <input type="email" id="email" required>
    </div>
    <button type="submit">Submit</button>
</form>
.form-group:has(input:invalid) {
    border: 2px solid red;
    padding: 10px;
}

Comparison with JavaScript

Before :has, achieving the same effect required JavaScript – querying the DOM, checking for child elements, and applying styles programmatically. CSS handles this natively now, which means fewer event listeners and simpler code.

Here’s how you can achieve the same result of Example #1 with vanilla javascript:

document.addEventListener("DOMContentLoaded", function() {
    const divs = document.querySelectorAll('div');

    divs.forEach(div => {
        if (div.querySelector('img')) {
            div.style.border = '2px solid green';
            div.style.padding = '10px';
        }
    });
});

The :has pseudo-class is fast in modern browsers, but unconstrained selectors like :has(img) without a type prefix force the engine to check every element on the page. Prefer constrained selectors like div:has(img) and use the direct child combinator div:has(> img) when you only care about immediate children.

Browser Support

The :has pseudo-class is supported by all major browsers since late 2023, covering roughly 93% of global users. Chrome 105+, Firefox 121+, Safari 15.4+, and Edge 105+ all handle it. You can use CSS @supports with @supports selector(:has(*)) for feature detection if you still need a fallback path.

Data on support for the css-has feature across the major browsers from caniuse.com

FAQs

What is the CSS :has() pseudo-class?
A relational pseudo-class from CSS Selectors Level 4 that lets you style a parent element based on its descendants. For example, div:has(img) targets any div that contains an img.
Is CSS :has() supported in all major browsers?
Yes. Chrome 105+, Firefox 121+, Safari 15.4+, and Edge 105+ support it, covering about 93% of users globally. It reached Baseline status in December 2023.
Can :has() replace JavaScript for parent selection?
For styling, yes. :has() handles parent-child styling natively in CSS without DOM queries or event listeners. JavaScript is still needed for logic beyond styling.
Does using :has() affect page performance?
Unconstrained selectors like :has(img) can slow rendering. Prefix with a type or class (div:has(img)) and use the direct child combinator (:has(> img)) to keep things fast.
Can I combine :has() with other pseudo-classes?
:has() composes with :not(), :is(), :where(), and state pseudo-classes like :checked or :invalid. For example, form:has(input:invalid) targets forms containing invalid inputs.

Conclusion

The :has pseudo-class gives CSS something developers wanted for years – true parent selectors. I use it regularly, and it simplifies layouts that previously needed JavaScript for conditional styling. Browser support is solid across the board, so go ahead and start using it. If you’re exploring other modern CSS features, check out native CSS nesting as well.

Join the Discussion
0 Comments  ]

Leave a Comment

To add code, use the buttons below. For instance, click the PHP button to insert PHP code within the shortcode. If you notice any typos, please let us know!

Savvy WordPress Development official logo