CSS the :not() selector
Tags: css, webdev, codepen
Published: 2020-09-02 10:24:43

## Intro
<a href="https://karsvaniersel.com/blog/css-coding-patterns-that-give-you-away-as-a-junior-developer" target="_blank" rel="noopener">In my previous post</a>
I wrote a bit about the `:not()` selector and I got a lot feedback that people never heard of this element. So I figured I would dedicate a post just to the `:not()` CSS selector.

## What is the :not() selector in CSS?
The `:not()` is a CSS <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-classes" target="_blank" rel="noopener">pseudo-class</a> that targets elements that *do not* match the selector given. Since it prevents specific items from being selected, it is known as the *negation pseudo-class*.

In essence you can target anything **except** what you put in the `:not()` selector.

Lets look at a quick example:

{% codepen https://codepen.io/karsviersel/pen/LYNzWpM %}

## :not() rules
There are a couple of rules when using the `:not()` selector. You should keep this in mind when using the `:not()` selector in your projects, cause they could cause unsual outcomes that have you burn hours trying to figure them out.

* You cannot nest the `:not()` pseudo-class, which means you cannot do `:not(:not(...))`
* You cannot use it with pseudo-elements such as `::before` and `::after`. It will work with `:first-child` and `:last-child` since they are simple selectors.
* Using the `:not()` selector can increase the specificity of a rule. `#foo:not(#bar)` will match the same element as the simpler `#foo` but with a higher specificity.
* Using just `:not(.class)` will match **anything** that isn't `.class` including `<html>` and `<body>`.
* The `:not()` selector only applies to one element; you cannot use it to exclude all ancestors. `body :not(table) a` will still apply to links inside of a table, since `<tr>` will amtch with the `:not()`

## How to use the :not() selector with multiple classes
It is possible to use the `:not()` selector with multiple classes.

Normally you would just want to do:
```css
p:not(.foo) {

}
```

But maybe you want to avoid multiple classes? There are no real combinators with `:not()` and you cannot nest them. But you can chain them, which works similar to `and`.

```css
p:not(.foo):not(.bar):not(.bold):not(.italic) {

}
```

## Tricks with :first-child, :last-child and :nth-child()
I use the `:not()` CSS selector most often with the `:first-child` or `:last-child` pseudo-class.

Think of having a list that you want to add some spacing to, but you don't want to last item to also have spacing at the bottom right? Well with `:not()` that is super easy to solve!

```css
li:not(:last-child) {
  margin-bottom: 20px;
}
```

This CSS will be applied to all `<li>` elements **except** the last child.

You could also do the reverse with `:first-child`
```css
li:not(:first-child) {
  margin-top: 20px;
}
```

Or use it with `:nth-child()`
```css
li:not(:nth-child(2)) {
  margin: 20px 0;
}
```

Here is a quick codepen sample to see it in action: 

{% codepen https://codepen.io/karsviersel/pen/abNLJVP %}


## Conclusion
A lot of handy things can be achieved by using the `:not()` CSS selector. I know I use it a lot of times, for menus, list items and what not. Even flexbox grids!

I hope you learned something from this post, and hopefully you can enhance your CSS skills with this knowledge.

Let me know how you apply the `:not()` selector, I'm always eager to new learn tricks with it.