Using the CSS :not() pseudo-class

Using the CSS :not() pseudo-class

Unleashing the Power of CSS :not() - Select What You Want, Exclude What You Don't!

The year is 2023, and CSS is continually improving. It is now possible to target not selected selectors like elements, classes, ids etc on a webpage using the CSS :not() pseudo-class

In this article, we are going to talk about how the CSS :not() pseudo-class (or :not() for short and read as not function) is used in production, how it can save you the stress of writing longer lines of CSS code and how we can tailor this to meet our specific needs.

Prerequisites

This article assumes that you at least know the basics of HTML, CSS and Javascript. You do not have to be an expert to follow along.

With that said, let's Dive in ๐Ÿฌ

What is the :not()?

According to the MDN, the :not() represents elements that do not match a list of selectors eg (elements, classes, ids). Since it prevents specific items from being selected, it is known as negation pseudo-class

In CSS, we exclude items with the :not(). The excluded items do not get the styling in the CSS rule.

<div class="container">
   <div class="box">This div has the box class</div>
   <div>This div does not have the box class</div>
   <div class="box">This div has the box class</div>
   <div>This div does not have the box class</div>
   <div class="box">This div has the box class</div>
   <div>This div does not have the box class</div>
 </div>
.container div:not(.box){
    border: 1px solid red;
}

/* The boxes that do not have the .box class will have a red border around it */

Anatomy of the : not()

:not(X){
    property: value;
}

/* X can be one or more CSS selectors eg elements, classes, ids  */

Looking at the Anatomy or Structure of the :not(), we can see the () after the :not which signifies that the :not() is Functional. It means that the :not() takes in arguments.

/* using the HTML code we used above earlier */

.container > div:not(.box, :nth-child(4)){
    border: 1px solid red;
}

/* All div elements with the .box class and the 4th direct child in the .container will not get styled. */

Things to note about the :not()

  1. The :not() Equivalence Theory.

    Note that we can chain two :not() together

     :not(.foo):not(.bar){
         border: 2px solid red;
     }
    

    This piece of code works but it does not look readable and can get messy real quick if more :not() are added.

    The code above is equivalent to

     :not(.foo, .bar){
         border: 2px solid red;
     }
    

    This is more readable and easy to understand.

  2. The not() does not accept Pseudo-elements, as arguments. Simply put using pseudo-elements as arguments to the not() makes the style invalid.

     /* Example */
     article:not(h2, ul, img::before) { }
    

    The img::before is a pseudo-element. This makes the CSS rule Invalid.

  3. The :not() is an unforgiving selector.

    If any selector passed to the :not() is invalid or not supported by the browser, the whole rule will be invalidated.

     /* Example */
     article:not(h2, ul, ::devyoma) { }
    

    The devyoma is totally invalid. A forgiving selector list disregards that false selector(::devyoma) and evaluates the remaining elements as though it were written as follows:

     /* Example */
     article:not(h2, ul) { }
    
  4. The :not() allows useless selectors to be written. Try to be careful when using the :not().

     :not(*){
         color: red;
     }
    
     /* The (*) represents all elements and therefore no element on the page will be styled */
    

:not() use-cases

  1. Selecting element(s) by excluding some. This is by far the basic use-case of the :not()

     <div class="container">
         <p class="first">This is a normal paragraph </p>
         <p class="second">This is a normal paragraph </p>
         <p>This is a normal paragraph </p>
         <p>This is a normal paragraph </p>
     </div>
    
     .container > p:not(.first, .second){
         border: 1px solid red;
     }
    

    The CSS code above gives a border line to the paragraph tags in the container div that do not have the .first and .second class.

  2. Styling other elements in a div excluding the first and/or the last child element of that div.

    Now, this is by far my favourite use-case of the :not()

     /* using the same html we have in use-case 1 */
    
     .container > p:not(:first-child, :last-child){
         border: 1px solid red;
     }
    

    NB: The > targets elements which are direct children of a particular element. You can read more about it here

  3. Improving Accessibility and Search Engine Optimization (SEO)

    Alt tags provide context to what an image is displaying, informing search engine crawlers and allowing them to index an image correctly.

    Images should have an alt attribute, even if it is empty i.e <img src="photo.jpg" alt=""/>

    Let us imagine we want to find images on our webpage that do not have the alt attribute, we can write the following CSS code to fish it out

     <div class="container">
         <img src="./images/gaara.jpg" alt="Gaara">
         <img src="./images/kakashi.jpg" >
         <img src="./images/jiraiya.jpg" alt="Jiraya">
         <img src="./images/minato.jpg" >
         <img src="./images/sai.jpg" alt="Sai">
     </div>
    
     .container > img:not([alt]){
         border: 3px dashed black;
     }
    

    Wrap Up

    The :not() is useful and has some important use-cases discussed above. We also sighted examples where we can write invalid styles using the :not().

    I am happy you read to this point and I would love it if you would not only read it but also put the :not() into practice. Happy Coding

    What are your thoughts on the :not()? Kindly share other instances where the :not() has been of help to you. Let us know in the comments section below.

    Thank you.