Not to mention
Extra
Manuel Matuzović wrote about the difference between :has(:not())
and :not(:has())
almost two years ago.
Another thing that may trip you up when using :not()
is going the opposite direction: While :has()
is about finding out about child nodes, what about selecting something further up in the DOM? Consider the following example.
:not(.specific) .element {
color: tomato;
}
Here we are changing the color of an .element
that does not have a .specific
ancestor. Well, changes are this is always the case. Unless every ancestor all the way up to <HTML>
has the .specific
class attached, our color will be applied.
For :not()
to make sense, we need to tie to something else. Sadly this requires us to have .something
to work with in the first place.
.something:not(.specific) .element {
color: tomato;
}
Now we target an .element
that is part of .something
, unless said something is .specific
.
So we are done?
Almost. There is a way to make the wildcard version actually useful.
:not(.specific) > .element {
color: tomato;
}
By adding the child combinator, we are not targeting any ancestor, but just the parent. While this obviously a bit limiting, targeting a parent that is not .specific
may at times be exactly what you need.
Update
Now we are done. Or so I thought. But Christopher Kirk-Nielsen reached out to inform me that by putting the ancestor inside :not()
we can get rid of the limitation. You can check out his article for all the details, I’ll just put the example below.
.element:not(.specific *) {
color: tomato;
}