Published at
Updated at
Reading time
2min

Today I came across a PR on MDN compatibility data that aims to update the CSS's support information for the :not() pseudo-class.

MDN defines :not() as follows:

The :not() CSS pseudo-class represents elements that do not match a list of selectors.

And before diving into the latest browser additions let's have a look at some examples selectors using :not().

/* Select elements that are
   not paragraphs */
:not(p) { /* ... */ }

/* Select paragraphs that
   don't have the class "fancy" */
p:not(.fancy) { /* ... */ }

/* Select elements that are
   not p or span */
:not(p):not(span) { /* ... */ }

/* Select elements that are
   not p or span */
:not(p, span) { /* ... */ }

What changed is that the :not() pseudo-class now has cross-browser support for complex selectors in CSS. What's a complex selector and why is it exciting when using :not()? Read on!

A selector that matches elements that are not descendants of other elements

I started reading the specification for CSS selectors. Reading specifications is never easy, but if you're curious the specification defines a complex selector as follows:

A complex selector is a sequence of one or more compound selectors separated by combinators.

I don't want to get into this topic here, but as far as I understand .foo .bar or div > span + .someClass are considered complex selectors (please correct me when I'm wrong).

What's exciting about supported complex selectors in :not() pseudo-classes is that it's possible to select elements that are not (!) children/descendants of other elements using the universal selector (*).

Let's say that you want to adopt image loading using the webp or avif format and want to select (and mark) all the img elements that are not children of a picture element, you can now do that! 🤯

In the example above, you see that the img element that is not a child of a picture element (and thus is not loading webp) is displayed with a red border.

Safari supports complex selectors in :not() since 2015, Firefox supports them since December 2020, and my Chrome just updated and now supports and the Chromiums with version v88, too.

That's a nifty trick I have to say!

Vincent De Oliveira pointed out that you can detect images that are not descendants of picture elements without a complex :not() selector: :not(picture) > img. And they're correct. Thanks for pointing that out!

If you enjoyed this article...

Join 6.3k readers and learn something new every week with Web Weekly.

Reply to this post and share your thoughts via good old email.
Stefan standing in the park in front of a green background

About Stefan Judis

Frontend nerd with over ten years of experience, freelance dev, "Today I Learned" blogger, conference speaker, and Open Source maintainer.

Related Topics

Related Articles