DEV Community

Cover image for ↔️ Sideway selection in CSS with :has()
Francesco Vetere
Francesco Vetere

Posted on

27 3 3 1 1

↔️ Sideway selection in CSS with :has()

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

AWS Security LIVE!

Join us for AWS Security LIVE!

Discover the future of cloud security. Tune in live for trends, tips, and solutions from AWS and AWS Partners.

Learn More

Top comments (6)

Collapse
 
morganney profile image
Morgan Ney

This has me excited.

Collapse
 
francescovetere profile image
Francesco Vetere

😂😂😂

Collapse
 
ben profile image
Ben Halpern

This is really helpful, thanks!

Collapse
 
francescovetere profile image
Francesco Vetere

Glad it helped! :)

Collapse
 
abdulmuminyqn profile image
Abdulmumin yaqeen

I super duper love the :has() 🫶

@devcanvas_ have a super cool demo on something like this.

you can find it here

Collapse
 
francescovetere profile image
Francesco Vetere

Cool stuff! 😍

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs