Historically, CSS has been a difficult language to work with. CSS preprocessors made it easier to work with CSS and also provided additional features like loops, mixins, and more. Over the years, CSS has gotten more capable and adopted some of the features originally introduced by CSS preprocessors. One such feature is "nested styling".



Nested Styling: The Old Way

Nested Styling is a feature available in many CSS preprocessors like Sass, Stylus, and Less CSS. Although the syntax might differ among these preprocessors, the underlying concept remains consistent. If you wanted to style all the h1 elements in a div with the class name of container, in regular CSS, you would write:

.container {
  background-color: #f2f2f2;
}

.container h1 {
  font-size: 44px;
}

In a CSS preprocessor like Less CSS, you implement nested styling like this:

.container{
    background-color: #f2f2f2;

    h1 {
        font-size:44px;
    }
}

The code block above achieves the same results as the regular CSS implementation but makes it easy for any developer reading the code to grasp what is going on. This sense of "hierarchy" was one of the biggest selling points of CSS preprocessors.


                            


The nesting tree can be nested to any depth without limitations, but it's essential to be cautious, as excessively deep nesting may lead to code verbosity.

Native Nested Styling in CSS

Not all browsers include support for native nested styling. The Can I use... website can help you check if your target browser supports this feature.


Native nested styling in CSS works similarly to CSS preprocessors, meaning that it is possible to nest any selector inside another. But there is one key difference that you should note. Take a look at the code block below:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Nested Styling in CSS</title>
  </head>
  <body>
    <div class="container">
      <h1>Hello from the children of planet Earth!</h1>
    </div>
    <style>
      .container {
        background-color: red;

        h1 {
          color: yellow;
        }
      }
    </style>
  </body>
</html>

In the code block above, the div with the class name container has a red background color. The styling for the h1 element lies in the .container block. This h1 element has the color yellow. When you run this code in the browser, you might notice something wrong. The browser correctly applies a red background color to the container div, but the h1 does not have the appropriate styling.

This is because nested styling work a bit differently in CSS compared to CSS preprocessors like Less. You cannot directly reference an HTML element in a nested tree. To fix this, you need to use an ampersand (&) as illustrated below:

.container {
       background-color: red;

    & h1 {
        color: yellow;
    }
}

In the code block above, & acts as a reference to the parent selector. Putting the ampersand before the h1 element should let the browser know that you are targeting all the child h1 elements on the container div. When you run the code in the browser, you should see the following:





Since & is the symbol used to reference a parent element, it is quite possible to target an element's pseudo-classes and pseudo-elements like this:

.parent1{
    &:hover{
        background-color: red;
    }
    &::before{
        content:"Here is a pseudo element.";
    }
}

Nesting Media Queries

Prior to the implementation of CSS nested styling, if you aimed to apply styles conditionally, depending on the browser width, you had to resort to a method like the following:

p {
    color:black;
}

@media (min-width:750px) {
    p {
        color:gray;
    }
}

When the browser renders the page, it determines the color of the p element based on the browser width. If the browser width exceeds 750px, it uses the color gray; otherwise, it applies the default color (black).

This implementation works fine, but as you can imagine, things can become pretty verbose quickly, especially when you need to apply different styles based on certain rules. It is now possible to nest media queries directly in the style block of an element.

p {
    color:black;

    @media (min-width:750px) {
        color:gray;
    }
}

This code block does basically the same thing as the previous one, but it comes with the advantage of being easy to understand. By merely looking at the media query and the nesting parent element, you can tell how the browser will apply the appropriate styles when the defined conditions are met.

Styling a Website With CSS Nested Styles

It is time to put everything you have learned so far into practice by building a simple website and leveraging the nested styling feature in CSS. Create a folder and name it whatever you want. In that folder, create an index.htm and a style.css file.

In the index.htm file, add the following boilerplate code:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css" />
    <title>Simple Website</title>
  </head>
  <body>
    <div class="container">
      <div class="article">
        <h1>Lorem ipsum dolor sit amet consectetur adipisicing elit.</h1>
        <div class="meta-data">
          <span class="author">David Uzondu</span>
          <span class="time">3 hours ago</span>
        </div>
        <div>
          Lorem ipsum dolor, sit amet consectetur adipisicing elit. Illo ut
          quasi hic sint dolorum sapiente magni ratione? Suscipit commodi ad,
          asperiores nostrum natus aperiam et alias, officiis dolorum ipsa vero
          minima consequatur recusandae quasi aliquid quibusdam ducimus eaque!
          Excepturi voluptas eveniet nemo, earum doloribus, soluta architecto
          iste repellat autem aspernatur beatae ut quis odio est voluptates sunt
          qui rerum blanditiis minus! Rerum labore nobis, odit quod amet dolorum
          quae laudantium.
        </div>
      </div>
      <div class="sidebar">
        <h2>Trending Articles</h2>
        <h4>Lorem ipsum, dolor sit amet consectetur adipisicing elit. Fugit, iusto ipsum!</h4>
      </div>
    </div>
  </body>
</html>

The code block above defines the markup for a mock news website. Next, open the style.css file and add the following code:

.container {
  display: flex;
  gap: 25px;

  @media(max-width:750px) {
   flex-direction: column;
  }
  

  .article{
  width:90%;
  }

  & div:nth-child(3) {
    text-align: justify;
  }

  & span {
    color: rgb(67, 66, 66);

    &:nth-child(1)::before {
      font-style: italic;
      content: "Written by ";
    }

    &:nth-child(2) {
      font-style: italic;
      &::before {
        content: " ~ ";
      }
    }
  }

  .meta-data {
    margin-bottom: 10px;
    padding-bottom: 10px;
    border-bottom: solid 1px;
  }

}

    

                                                                  

The code block above styles the website entirely with CSS nested styling. The .container selector acts as the root depth. You can make reference to this selector using the & symbol. When you run the code in the browser, you should see the following:

Screenshot of the finished website


Do You Still Need a CSS Preprocessor?

With the introduction of nested styles to native CSS, CSS preprocessors might appear to be unnecessary. However, it's crucial to keep in mind that CSS preprocessors offer more than just nested styling. They provide features like loops, mixins, functions, and more. Ultimately, whether to use a CSS preprocessor or not depends on your specific use case and personal preferences.