- The negation pseudo-class selector is one of the oddest selectors in all of CSS. Essentially, it allows you to target everything that doesn't match a simple selector that you pass into it as an argument. It's a little easier to understand if you can see how it works. So let's take a look at the syntax and then we'll experiment with it. So I've got the not.htm file from the 04_05 directory opened up in a browser, and the first thing I want to take a look at are the three bullet points of sort of a syntax example that I have here.
So the very first example I have there where it says :not(p), that would match every element except for paragraphs. The one underneath it where we're a little more element specific, we're saying p:not and inside of that we're passing the attribute selector of class. That would target every single paragraph that doesn't have a class attribute. And then finally underneath it, you can see li:not, and then inside the parentheses the pseudo-class selector of last-child.
So that would match every item in a list except for the last one. So now that we have a handle on the syntax, let's experiment a little bit with how it actually works. So I'm gonna open up the same file inside my code editor, and I want to go up into the head of the document where our styles go. And directly underneath that styles, we're just gonna experiment with the selector first. So the first thing I'm gonna do is I'm gonna do :not, and then in parentheses (h1). So that is gonna match every element except for heading ones.
And what I'm gonna do with that, something so we can really see the effect. I'm gonna change the color to red. Now if I do that once we're back out in the browser, when I refresh that you can see that everything except for the heading one, CSS Selectors, up here has turned red. Everything that is that doesn't already have an explicit color definition. One thing you need to remember about the negation selector is it has a pretty low degree of specificity so it is pretty easy to overwrite. In this case of our browser compatibility tables, the class selector here that's controlling their color is overriding that.
Now sometimes the negation selector might work in a way that you didn't exactly anticipate. For example, so I'm gonna take the existing negation selector we have and change it from :not(h1) to :not(p) so this way they essentially target everything on the page that is not a paragraph. Well, if I save this and go back out to the browser and refresh, you would expect that everything except for the paragraphs to be red. But in fact, the paragraphs are for the most part all red. So what's happening here? Well the other thing that we have to understand is inheritance.
Because it's matching every single element that's not a paragraph, that would also match the parents of those paragraphs so the articles and the sections that they're inside of. And since the paragraphs don't have an explicit color defined, they're going ahead and inheriting that color from their parents. So sometimes it might actually match the elements you'd expect it to, but not always have the effect you expect it to. Okay, so the next thing I want to do is get a little bit more specific with the elements that we're targeting. If I scroll down in my code to the example section, you can see that inside the article with the class of example we have a heading three followed by a heading four, and then we have a paragraph followed by two more paragraphs.
Now in both of the paragraphs that follow that have classes. One has a class of second. The other one has a class of third. Then we have a heading four, and below that we have an unordered list. Now the unordered list has 10 things inside of it or 10 list items, and each of them has a class attribute applied to it. Take a look at the classes. There are three classes that area applied to these list items; tip, sample and current. Some have all three. Some only have one or two, but it's a combination of those three classes; tip, sample, and current.
Okay, so let's go back up and modify our negation selector. The first thing I'm gonna do is I'm gonna scope it so that it's limited to affecting only the example area. To do that I'm gonna use a descendant selector so I'm gonna start by .example, and doing a space before our negation selector, and then I'm gonna get element specific with the negation selector. I'm gonna do p, so p:not. So now I'm targeting paragraphs and I want to exclude certain paragraphs. So the paragraphs I want to exclude from being matched by the selector is gonna go inside the argument.
And inside the argument, I'm gonna pass an attribute selector so left bracket, and I'm just gonna do the attribute class. Now let's do something besides just changing the color of that. Let's change the font-family. So I'm gonna do font-family, and I'm just gonna do Georgia, Times, and then serif. So we're saying go into that example area, find every paragraph, and match the ones that don't have a class attribute. So if I save that and refresh my browser, now if I scroll down into the example area, you can see that only the first paragraph is matching.
The second and third paragraph have the class attribute even though they have different values. We were able to be more specific with targeting certain paragraphs, but we could still be general and since we were saying, hey, just any paragraph that doesn't have a class attribute, the actual value of the class attribute doesn't matter although we certainly could be that specific if we wanted to be. Speaking of being a little more specific, let's go in and start targeting our list items. So I want to write a new selector that's gonna target some of the list items down there in the list, and I want to be a lot more specific about it.
I want to target them based on which classes are or are not applied to them. All right, so what I'm gonna do is a new selector that's li.tip. So that is an element specific class selector. We're saying go find all the list items with a class of tip applied to them. Now, I'm gonna be even more specific with that and do a not pseudo-class selector, so :not, no space there, and then I'm gonna pass into that the class of current. Open and close my curly braces, and then I'm gonna do a color of red.
So let's think about what this is actually doing. We're saying go find every single list item in the class of tip. But, in addition to having a class of tip, we want to make sure it also doesn't have the class current applied to it. So if I save this, go into the browser and refresh this, you can see that only four, five, and nine meet that criteria. If we go into the code to check that, indeed Thing four just has tip and sample. Thing five has tip; whereas Thing nine has both tip and sample.
But none of those have current. Now, Thing eight doesn't have current, but it's just sample. So we could modify this any way that we wanted to. We could instead of targeting those list items that don't have current applied to them, we could do the ones that don't also have sample applied to them. If we refresh, we can see that that would now return three, five, and six. And indeed, looking at the code, three has tip and current. Five just has tip, and six has tip and current, but no sample. So that's one of the really neat things that the negation selector allows you to do is to filter out results based on different types of attributes or elements that are not found in your targeted area.
Now I know I used classes a lot in this example, but you can pass other elements, other attributes, things like IDs, classes like we used, and other pseudo-class selectors into the not argument. The only things you can't pass into it are other negation selectors or pseudo-element selectors. While this makes them really powerful, it's definitely a selector you want to plan carefully before you use. Make sure you keep in mind all of the use cases that it could match in order to make sure that it behaves exactly the way that you intended.
- Targeting classes and IDs
- Working with group selectors
- Targeting element attributes
- String matching
- Targeting links with pseudo-class selectors
- Targeting child elements and empty elements
- Targeting parent, child, and sibling elements
- Matching patterns
- Writing efficient selectors