MakeUseOf logo

The Differences Between Native CSS and Sass Nesting

Woman working on a laptop computer, on a bed.
Created by Kingsley Ubah via mockup.photos.
Kingsley is a freelance web developer from Nigeria. He has been writing JavaScript and Node.js professionally for over 3 years. During this time, he has worked with clients from all across the globe. Kingsley also educates developers via his writing. He writes for several tech-based publications and agencies, including FreeCodeCamp, Tutsplus, ContentLab, and MakeUseOf.
Sign in to your MakeUseOf account

Since it launched, CSS has doggedly refused to support a syntax for nesting selectors. The alternative has always been to use a CSS preprocessor like Sass. But today, nesting is officially part of native CSS. You can try out this feature directly in modern browsers.

If you’re migrating from Sass, you’ll need to take into account any differences between native nesting and Sass nesting. There are some key differences between both nesting features, and being aware of them is crucial if you're making the switch.

You Need to Use "&" With Element Selectors in Native CSS

CSS Nesting is still a draft specification, with varying browser support. Make sure to check sites like caniuse.com for up-to-date information.

Here’s an example of the type of nesting you would see in Sass, using the SCSS syntax:

.nav {
 ul { display: flex; }
 a { color: black; }
}

This CSS block specifies that any unordered list inside an element with a nav class aligns as a flex column, one way of laying out HTML elements on the page. In addition, all anchor link text inside elements with a nav class should be black.

Now, in native CSS, that kind of nesting would be invalid. To make it work, you'd have to include the ampersand symbol (&) in front of the nested elements, like so:

.nav {
 & ul { display: flex; }
 & a { color: black; }
}

The early version of CSS nesting didn't allow the nesting of type selectors. A recent change means you no longer have to use "&", but older versions of Chrome and Safari may not support this updated syntax yet.

Now if you were using a selector that starts with a symbol (e.g. class selector) to target a specific part of the page, you can omit the ampersand. So the following syntax would work in both native CSS and Sass:

.nav {
 .nav-list { display: flex; }
 .nav-link { color: black; }
}

You Can't Create a New Selector Using "&" in Native CSS

One of the features you probably love about Sass is the ability to do something like this:

.nav {
 &-list { display: flex; }
 &-link { color: black; }
}

This Sass code compiles to the following raw CSS:

.nav-list {
 display: flex;
}
.nav-link {
 color: black;
}

In native CSS, you can't create a new selector using "&". The Sass compiler replaces the "&" with the parent element (e.g. .nav), but native CSS will treat the "&" and the part after it as two separate selectors. As a result, it will try to make a compound selector, which won't give the same result.

This example will work in native CSS, though:

.nav {
 &.nav-list { display: flex; }
 &.nav-link { color: black; }
}

This works because the first selector is the same as nav.nav-list in plain CSS, and the second is the same as nav.nav-link. Adding a space between the "&" and the selector would be equivalent to writing nav .nav-list.

In native CSS, if you use the ampersand like this:

.nav {
 &__nav-list { display: flex; }
 &__nav-link { color: black; }
}

It's the same as writing this:

__nav-list.nav {
 display: flex;
}
__nav-link.nav {
 color: black;
}

This might come as a surprise to you, considering that both the __nav-list and __nav-link are inside the .nav selector. But the ampersand actually places the nested elements in front of the parent element.

Specificity Can Be Different

Another thing to note is the impact on specificity that doesn't happen in Sass but happens in native CSS nesting.

So let's say you have a <main> and an <article> element. With the following CSS, an <h2> in either of these elements will use a serif font:

#main, article {
 h2 {
 font-family: serif;
 }
}

The compiled version of the above Sass code is as follows:

#main h2,
article h2 {
 font-family: serif;
}

But the same nesting syntax in native CSS will produce a different result, effectively the same as:

:is(#main, article) h2 {
 font-family: serif;
}

The is() selector handles specificity rules slightly differently from Sass nesting. Basically, the specificity of :is() gets auto-upgraded to the most specific item in the list of arguments provided.

The Order of Elements Might Change the Selected Element

Nesting in native CSS can completely change what the selector actually means (i.e. selects a completely different element).

Consider the following HTML, for example:

<div class="dark-theme">
 <div class="call-to-action">
 <div class="heading"> Hello </div>
 </div>
</div>

And the following CSS:

body { font-size: 5rem; }
.call-to-action .heading {
 .dark-theme & {
 padding: 0.25rem;
 background: hsl(42, 72%, 61%);
 color: #111;
 }
}

This is the result if you use Sass as the CSS compiler:

[画像:Screenshot of the page]
Screenshot by Kingsley Ubah -- no attribution required

Now in the HTML block, if you were to move the <div> with the class of dark-theme inside that of call-to-action, it would break the selector (in Sass mode). But when you switch to regular CSS (i.e. no CSS preprocessor), the styles will continue to work.

This is because of the way that the :is() works under the hood. So the above nested CSS compiles into the following plain CSS:

.dark-theme :is(.call-to-action .heading) {
 /* CSS code */
}

This is specifying a .heading that is a descendant of both .dark-theme and .call-to-action. But the order of these doesn't really matter. As long as the .heading is the descendant of .call-to-action and .dark-theme, it works in either order.

This is an edge case and not something you'll run into that often. But understanding the :is() selector's underlying functionality can help you master how nesting works in CSS. This also makes debugging your CSS much easier.

Learn How to Use Sass in React

Because Sass compiles to CSS, you can use it with virtually any UI framework. You can install the CSS preprocessor in Vue, Preact, Svelte, and—of course—React projects. The setup process for Sass for all these frameworks is also quite straightforward.

The biggest advantage of using Sass in React is that it lets you write clean, reusable styles using variables and mixins. As a React developer, knowing how to use Sass will help you write cleaner, more efficient code and make you a better developer overall.

AltStyle によって変換されたページ (->オリジナル) /