DEV Community

Samantha Ming
Samantha Ming

Posted on

CSS :not Selector

Code Tidbit by SamanthaMing.com

Instead of using 2 different selectors to assign styling and then another to negate it. Use the :not selector to select every element except those that match the argument you passed through 👍

/* ❌ */

li {
  margin-right: 10px;
}

li:first-of-type {
  margin-right: 0;
}

/* ✅ Much Better */

li:not(:first-of-type) {
  margin-right: 10px;
}
Enter fullscreen mode Exit fullscreen mode

Allowed Arguments

In the current draft, CSS Selectors Level 3, you can only pass simple selector as your argument.

Simple Selectors:

  • Type Selector
  • Universal Selector
  • Attribute Selector
  • Class Selector
  • ID Selector
  • Pseudo-class
/* Type */
h1 {}

/* Universal */
* {}

/* Attribute */
a[title] {}

/* Class */
.parent {}

/* ID */
#demo {}

/* Pseudo-class */
:first-child {}
Enter fullscreen mode Exit fullscreen mode

CSS Versioning Briefly Explained

Just like how JavaScript or ECMAScript have different versions. CSS also have different versions. However, unlike ECMAScript where everything is under one huge category (ES5, ES6, ES7), CSS works in chunks.

For example, they have CSS Selectors Level 3, CSS Grid Layout Level 1, and CSS Flexbox Level 1. The :not selector falls under the CSS Selectors Level 3 specification. The next one that the CSS Working Group is working on is...hint, what comes after 3...ding ding, CSS Selectors Level 4 😜

Rachel Andrew wrote a fantastic article explaining CSS Levels, I also linked it in the Resource section, so have a read if you're interested 🤓

Passing a list of selectors

In the current version, you can only pass in simple selectors as your argument. However, in CSS Selectors Level 4, you will be able to pass in a list of selectors. So cool, right 👏.

/* CSS Selectors Level 3 */
p:not(:first-of-type):not(.special) {}

/* CSS Selectors Level 4 */
p:not(:first-of-type, .special) {}
Enter fullscreen mode Exit fullscreen mode

And here is what will be selected

<div>
  <p>1</p>
  <p>2</p><!-- selected -->
  <p>3</p><!-- selected -->
  <p class="special">4</p>
  <p>5</p><!-- selected -->
</div>
Enter fullscreen mode Exit fullscreen mode

Nesting Negations not allowed 🙈

One thing to point out is that negations maybe not be nested. So this is a no-no:

:not(:not(...)) {}
Enter fullscreen mode Exit fullscreen mode

:first-child vs :first-of-type

Let's start by defining them individually:

:first-child only selects the first element IF it is the first child of its parent. That means if it's not the first child of the parent, nothing will be selected.

:first-of-type will select the first element of the type you specified. Even if it's not the first child of its parent. So a result will always appear if you use this selector (unless you picked an element that doesn't exist at all).

Alright, let's look at some examples.

Children are all the same type

Because the child type is all the same, the result is the same for both.

<div>
  <p></p> <!-- p:first-child, p:first-of-type -->
  <p></p>
</div>
Enter fullscreen mode Exit fullscreen mode

Children are different types

<div>
  <h1></h1>
  <p></p> <!-- p:first-of-type -->
  <p></p>
</div>
Enter fullscreen mode Exit fullscreen mode

BUT because p is no longer the first child. If you call p:first-child, NOTHING will be selected.

<!-- ⚠️ p:first-child ➡️ no element selected -->
<div>
  <h1></h1>
  <p></p>
  <p></p>
</div>
Enter fullscreen mode Exit fullscreen mode

Selecting First Child

So you might be wondering, what if I don't care about the type, I just want to select the first child of its parent. In that case, you can do this:

.parent :first-child {
  color: blue;
}
Enter fullscreen mode Exit fullscreen mode
<div class="parent">
  <h1></h1><!-- selected -->
  <p></p>
  <p></p>
</div>
Enter fullscreen mode Exit fullscreen mode

Other similar CSS pseudo-class

And this understanding applies to the other cousin classes:

  • :last-child and :last-of-type
  • :nth-child and :nth-of-type
  • :only-child and only-of-type

Browser Support

The :not selector is supported by most modern browsers and Internet Explorer 9 and up.

Browser compatibility

Resources


Thanks for reading ❤
Say Hello! Instagram | Twitter | Facebook | Medium | Blog

Top comments (8)

Collapse
 
gmartigny profile image
Guillaume Martigny

Nice post.

I just want to add one caveat of the :not selector:
It's quite expensive when working on low-performance environment. (let's be clear, I'm not talking about regular personal computer.)

CSS parse selector from right to left. So for this :

li:not(:first-of-type) {
}
Enter fullscreen mode Exit fullscreen mode

The parser will select all nodes being :first-of-type (potentially a lot). Then apply the inverse with the :not, and finally keeping only the li tag among them.

Given :not is never the only way to do something in CSS, if you really care for performance, avoid the :not selector. (in the end, it's very useful and I use it on personal projects)

Collapse
 
samanthaming profile image
Samantha Ming

Very good point! Something to definitely keep in mind when choosing what kind of CSS selector to use. Thanks for sharing this insight 👍

Collapse
 
link2twenty profile image
Andrew Bone • Edited

I often use not to prevent hidden from being overwritten.

.card:not([hidden]) {
  display: inline-flex
}
<div hidden class="card">
  Some card content
</div>

Without the not the HTML would display the content even though we want it to be hidden.

Collapse
 
samanthaming profile image
Samantha Ming

WOOO! I like this example! Thanks for sharing 💯

Collapse
 
mkrl profile image
Mikhail Korolev

Great writeup! I love the diversity of css selectors until the point when you actually need to use them in production. One of my past co-workers once said:

"If you need more than 2 level deep css selectors in production app, you are doing it wrong."

When both front and back-end parts are working together on a healthy project following simple rules like BEM methodology or something else of a similar nature, you should not have to use complex selectors. I'm not saying that this should be taken as a fundamental truth, but speaking from my humble experience, that saves nerves for all the gears of the development machine.

And of course yes, you absolutely need to know this stuff. Simply, just try not to be forced to use it on a regular basis :)

Collapse
 
samanthaming profile image
Samantha Ming

I think you hit such an important point! When we implement something like BEM, complex selectors are really not needed. And that's probably better for performance as well. BEM is something I'm trying to utilize more of, not only does it avoid some crazy CSS selections but it's so much easier to follow the components. I just have to get use to the dashes and underscores 😝

Collapse
 
bitdweller profile image
Pedro Pimenta

Nice technique on the :not(:first-of-type), it's much cleaner although can cause performance issues. I like it, though! Also, thanks for showing me :only-child, I had no idea!

Collapse
 
samanthaming profile image
Samantha Ming

I wonder if it's because the performance, that's why IE didn't pick it up. Or maybe that's just IE being IE lol. :only-child is pretty neat, I'll have to play around with it some more and find some interesting examples, then that will be my next post 😀