We can use :has, finally!
A dive into the most anticipated CSS feature
For years, CSS developers have wished for the ability to select an element based on its content. Although CSS provides selectors that can select elements based on a lot of characteristics, until recently there was no way to select an element based on what it contained.
Fortunately, the introduction of :has()
changed this. This new feature is a game-changer, as it allows you to select an element based on its content.
In this post, we’ll dive into one of the most anticipated CSS features: the :has
pseudo-class. And it turns out to be much more than “just” a parent selector.
The Syntax
The :has
pseudo-class is used to select elements based on their contents. It is applied to the element we want to apply rules to, and we pass it to the selector of the element it should contain:
// Here we target any element with the
// class `post` containing an `h1`
.post:has(h1){
background-color: teal;
}
Using :has
as a parent selector
Using :has
as a parent selector can simplify many situations. Here are some examples that come to mind:
-
On some pages of your app, you may want to change the global font size or background color of the
body
element. Previously, before the:has
pseudo-class was introduced, we would have needed the backend to toggle some HTML class based on the page type. However, with a parent selector, this is now trivial:body:has(.container.legal-mentions) { font-size: 80%; }
-
On our list of blog posts, we want posts to change not have margin if the post contains an image:
.post:has(img){ margin-left:0; }
This is extremely powerful in itself, but we can do even more when using combinators.
Going further with Combinators
Combinators combine other selectors in a way that gives them a useful relationship to each other and the location of content in the document.
— MDN
We can use the child combinator >
inside has
to ensure that we are selecting a direct child element. For example, to select a div
element that has a hr
element as a direct child, we can use the selector div:has(>hr)
.
We can use the adjacent sibling combinator +
to target an element followed by another element. For example, to select a title followed by a subtitle, we can use title:has(+.subtitle)
.
Combining with other Pseudo-classes
Changing the style of a container when hovering over a child element sounds pretty cool, doesn't it?
We can achieve this by combining has
with hover
. For example, if we want a container to have a border whenever one of its links is hovered, we would use the following code:
.container:has(a:hover){
border: 2px solid pink;
}
Browser support
As of June 2023, the :has
pseudo-class is missing only in Firefox. However, it is behind a flag, so it should be supported soon!
Conclusion
The :has
pseudo-class is a powerful addition to the CSS selector arsenal. It allows you to select elements based on their contents, which can simplify many situations and make your code more maintainable. By using combinators, you can further refine your selections and achieve even more advanced effects.
While it is still missing in Firefox, it is expected to be supported soon. As always, make sure to test your code in all major browsers before deploying it to production.
Thanks for reading, and happy coding!
Learn how to use combinators and other pseudo-classes to achieve even more advanced effects.
Sources and Links
- https://developer.mozilla.org/en-US/docs/Web/CSS/:has
- https://webkit.org/blog/13096/css-has-pseudo-class/
- https://blog.logrocket.com/how-when-use-css-has-selector/
- https://css-tricks.com/the-css-has-selector/
I'm Tom Quinonero, I write about design systems and CSS, Follow me on twitter for more tips and resources 🤙