Magic PostCSS Custom Combinators using :has()

Similar to how you can (ab)use :nth-child() to create “new” CSS selectors, you can leverage :has() to create some typical combinators. Brandon McConnell did just that:

  • y:has(+ x) selects the first preceding y sibling of x:

  • y:has(~ x) selects all preceding y sibling of x:

  • x + y, y:has(+ x) selects the first preceding and first succeeding y siblings of x:

And those are just the simple ones. Selecting “all preceding y elements up to the third one” for example is possible using y:has(~ * + * + x) 😅

🤔 Not familiar with the CSS :has() selector? Read up on it right here.


To more easily work with that, Brandon also created a (still unpublished?) PostCSS plugin that supports fictitious CSS Selectors which automatically translate to their working counterparts. For example:

  • x - y translates to y:has(+ x)
  • x -- y translates to y:has(~ x)
  • x % y translates to x + y, y:has(+ x)

Here’s a pen with all combinators he came up with:

Oh that’s clever! Perhaps we might one day see these selectors land in CSS itself?

👨‍🔬 Only Safari Technology Preview 137 supports :has() at the time of writing, so you’ll need to use that browser to see anything get colored in the “Actually Rendered” rows there.

During his work Brandon noticed a bug in Safari’s implementation in which it selects some non-targeted elements, so you might see some faulty ones.

Published by Bramus!

Bramus is a frontend web developer from Belgium, working as a Chrome Developer Relations Engineer at Google. From the moment he discovered view-source at the age of 14 (way back in 1997), he fell in love with the web and has been tinkering with it ever since (more …)

Leave a comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.