Understanding the CSS :has()
Pseudo-class
The :has()
pseudo-class is a powerful addition to CSS Selectors Level 4, enabling developers to select elements based on their descendants or subsequent elements. It essentially brings parent selection capabilities to CSS, allowing for more dynamic and responsive styling without relying heavily on JavaScript.
What Is the :has()
Pseudo-class?
The :has()
pseudo-class allows you to select an element if it contains at least one element that matches the selector passed into the :has()
function. It acts as a "parent" selector, which was not possible with previous CSS versions.
Syntax
The basic syntax of the :has()
pseudo-class is:
selector:has(selectorList)
Here, selector
is the element you want to select if it contains the elements specified in selectorList
.
Examples of Usage
Example 1: Styling a Parent Element Based on Its Child
Suppose you want to style any <div>
that contains an <img>
element:
/* CSS */
div:has(img) {
border: 2px solid blue;
}
/* HTML */
<div>
<p>This is a paragraph.</p>
</div>
<div>
<img src="image.jpg" alt="Example Image">
</div>
In this example, only the second <div>
will have a blue border because it contains an <img>
element.
Example 2: Selecting Siblings Based on Following Elements
You can use :has()
to select an element based on its subsequent siblings. For instance, style any <h2>
that is immediately followed by a <h3>
:
/* CSS */
h2:has(+ h3) {
color: green;
}
/* HTML */
<h2>Section Title</h2>
<p>Some content here.</p>
<h2>Another Section</h2>
<h3>Subsection</h3>
<p>More content here.</p>
In this case, the second <h2>
will have green text because it is immediately followed by an <h3>
element.
Example 3: Enhancing Forms Based on Input States
Style a <form>
element if any of its inputs are invalid:
/* CSS */
form:has(input:invalid) {
border: 2px solid red;
}
/* HTML */
<form>
<input type="email" required>
<button type="submit">Submit</button>
</form>
If the email input is invalid (e.g., empty or not a valid email address), the form will have a red border.
Advanced Usage
Example 4: Dropdown Navigation Menu
Show a dropdown icon next to navigation items that have a submenu:
/* CSS */
nav ul li:has(ul) > a::after {
content: ' ▼';
}
/* HTML */
<nav>
<ul>
<li><a href="#">Home</a></li>
<li>
<a href="#">Services</a>
<ul>
<li><a href="#">Consulting</a></li>
<li><a href="#">Support</a></li>
</ul>
</li>
<li><a href="#">Contact</a></li>
</ul>
</nav>
Only the "Services" menu item will have a dropdown arrow because it contains a nested <ul>
element.
Example 5: Styling Empty State Messages
Hide the empty state message if a container has any child elements:
/* CSS */
.container:has(> *) .empty-message {
display: none;
}
/* HTML */
<div class="container">
<p class="empty-message">No items available.</p>
<!-- Items will be inserted here dynamically -->
</div>
When items are added to the .container
, the empty message will be hidden automatically.
Browser Support
As of October 2023, the :has()
pseudo-class is supported in the latest versions of most major browsers:
- Google Chrome: Supported from version 105 onwards.
- Mozilla Firefox: Supported from version 103 onwards.
- Microsoft Edge: Supported from version 105 onwards.
- Safari: Supported from version 15.4 onwards.
- Opera: Supported from version 91 onwards.
Note that older browser versions and Internet Explorer do not support :has()
. Always ensure to test your styles in the browsers your audience is likely to use.
Performance Considerations
While the :has()
pseudo-class is incredibly powerful, it can impact performance, especially when used extensively or with complex selectors. To minimize performance issues:
- Use simple and specific selectors inside
:has()
. - Avoid using universal selectors (
*
) inside:has()
. - Limit the use of
:has()
to critical styling requirements.
Use Cases for :has()
The :has()
pseudo-class opens up new possibilities in CSS:
- Parent styling based on child elements: Style a parent when it contains certain child elements.
- Interactive components: Create more dynamic interactions without JavaScript.
- Form validation styling: Style forms or inputs based on validation states.
- Conditional layouts: Adjust layouts depending on the presence of elements.
Conclusion
The :has()
pseudo-class is a game-changer for CSS, bringing parent selection and more dynamic styling capabilities to the language. By understanding how to use it effectively, you can create more responsive and interactive designs with less reliance on JavaScript.