Published at
Updated at
Reading time

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!

Was this snippet helpful?
Yes? Cool! You might want to check out Web Weekly for more snippets. The last edition went out 8 days ago.
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