↔️ Sideway selection in CSS with :has()

Francesco Vetere - Jan 31 - - Dev Community

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, where a: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) {
  /* ... */
}
Enter fullscreen mode Exit fullscreen mode

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 */
}
Enter fullscreen mode Exit fullscreen mode

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! 👋

. . . . . .
Terabox Video Player