The Negation Pseudo-class

A few weeks back I tweeted a bit of CSS I’ve been using frequently and was quite surprised by the response, thus I wanted to share it here too. What was the bit of CSS? Simply enough, it was the following selector:

1
li:not(:last-child)

Often when working with lists we want to apply a specific style to all of the li elements in a list except for one, most commonly the first or last li element. In the past we’ve been known to write the following CSS:

1
2
3
4
5
6
li {
  border-bottom: 1px solid #ccc;
}
li:last-child {
  border: none;
}

The problem here is that we’ve defined styles only to overwrite them later by way of a higher specificity selector, in this case by adding the :last-child pseudo-class. In doing so we create extra work for the browser and slow down the rendering of these styles.

Instead of creating unnecessary work and overwriting our existing styles we can use the :not() negation pseudo-class in combination with another structural or position based pseudo-class, most commonly :first-child or :last-child, to more precisely scope our styles. Our more performant CSS would look like:

1
2
3
li:not(:last-child) {
  border-bottom: 1px solid #ccc;
}

For reference you can see the CSS above in action on CodePen.

Here we’re not overwriting any existing styles as we’re only applying style to the elements we wish. Additionally, browser support isn’t any different than before as the :not(), :first-child, and :last-child pseudo-classes have the same browser support.

If you’re using a “.last” class or structural or position based pseudo-class to overwrite existing styles I’d highly recommend moving in the direction of the :not() negation pseudo-class. Over time I’ve found myself using it in quite compelling situations, and writing truly performant CSS.

If you have any comments or questions please reach out on Twitter, I’d love to hear if, and how, you’re using the :not() negation pseudo-class.

Ask a question or share this article, we’d love to hear from you!