Hi folks! 👋 Today I would like to share with you this codepen I created in order to showcase a simple but really cool use for the recently introduced :has()
selector.
If you hover with your mouse over any of the emojis, you'll notice that not only the hovered emoji smoothly pops up, but its previous and next siblings also get affected a little bit, creating a very pleasant effect.
This cool effect is only possible thanks to the :has()
selector, recently introduced in the CSS world and now available for all the major browsers.
➡️ :has()
is a functional pseudo-class that allows us to style an element based on its descendants or any succeeding elements.
Basically,
:has()
allows to style the element it is attached to — otherwise known as the target element. This is similar to other pseudo-classes like:hover
, wherea:hover
is intended to style the<a>
element in an hovered state.However,
:has()
is also similar to:is()
,:where()
, and:not()
, in that it accepts a a list of relative selectors within its parentheses. This allows:has()
to create complex criteria to test against, making it a very powerful selector.
For example, if I wanted to select all the <article>
elements that contain an <img>
as child, :has()
would make this quite a simple task:
article:has(img) {
/* ... */
}
This use of :has()
is certainly one of the most common: it basically acts as a parent selector, something that really was missing in the web platform and was highly demanded for years by developers.
❗ BUT, because :has()
actually accepts a relative selector list as its argument, you can select so much more than just the parent element! Using various CSS combinators, it is now possible to not only go up ⬆️ the DOM tree, but also do sideway selections! ↔️
For example, article:has(+ article)
will select any <article>
element that has another <article>
as a direct sibling. This apparently simple selection would just not be possible without :has()
, and it would have required some extra JavaScript.
💡 The codepen I realized takes advantage of this very idea. I basically want to apply some styling (a scaling and a translation) for the currently hovered emoji, but also for its previous and next sibling.
➡️ :has()
makes this really easy:
.dock li:hover {
/* scale and translate the hovered emoji */
}
.dock li:hover + li {
/* scale and translate the next emoji */
}
.dock li:has(+ li:hover) {
/* scale and translate the previous emoji */
}
Of course the full code is a little bit more complex than that (you can check out the codepen if you're curious), but the main idea really is based on this simple snippet. Having a way to select not only an element and its next sibling, but also its previous one, opens up a whole new world of possibilities.
And that's it! Feel free to leave a comment and let me know what other cool stuff you built using :has()
😉
Till next time! 👋
Top comments (6)
This
has
me excited.😂😂😂
This is really helpful, thanks!
Glad it helped! :)
I super duper love the :has() 🫶
@devcanvas_ have a super cool demo on something like this.
you can find it here
Cool stuff! 😍