DEV Community

Cover image for CSS nesting is coming
Alvaro Montoro
Alvaro Montoro

Posted on • Updated on • Originally published at alvaromontoro.com

CSS nesting is coming

Browsing caniuse.com the other day, I found a pleasant surprise: a little green flag in a red box for a feature I'd been waiting for a long time.

CSS nesting will soon be supported on Chrome:

screenshot of caniuse.com for css nesting: all boxes are in red (not supported) except one that is in red with a tiny red flag (indicating that it will be available as an experimental feature behind a flag): Chrome 109 to 111

Yes, it's behind a flag and only in future versions, but it is a huge step forward. Those versions will soon be available, and we can try it locally (unfortunately, not on production without a polyfill or a plugin).

I can't wait for the table above to slowly start turning green. It will be big and could, little by little, reduce the dependency on libraries like Sass or Less. (Nothing against them, but it would be nice to have some of that behavior natively... I can only dream of having loops and functions one day.)

Not everyone shares my excitement. After sharing a post about this on social media, I quickly got some replies indicating that the nesting is no more than some syntactic sugar or not a significant improvement.

While it is true that it can be seen as syntactic sugar –some of the things we can achieve with CSS nesting can be achieved with combinators, too–; the critical part here is the "some" part. We can do some things with CSS nesting that cannot be done with combinators (e.g., styling pseudo-elements).

And even if we consider CSS Nesting syntactic sugar, where is the problem? Anything that helps organize the code, making it more robust, portable, and maintainable, should be welcomed. And that's what CSS nesting does: it allows grouping and encapsulating styles (in a similar way to how Sass or Less do it), and that will reduce common errors caused by poor code architecture/organization (like when people complain that changing a style in one page affects the styles on a different page.)

What is CSS Nesting?

This article was not intended to be a deep dive into CSS Nesting, more of an informational thing. The module is going through major updates and the notation displayed below may not match the final notation. If you want to learn more about CSS Nesting, check the W3C Editor's Draft, or Kilian Valkhof's article on CSS Nesting and Specificity.

With CSS Nesting, we can place one CSS rule inside of another (nest rules), and the selector of the child rule will be relative to the selector of the parent rule.

This is helpful for the modularization and maintainability of the code. Things that were exclusive to CSS preprocessors are possible in a native way.

Let's imagine that we have this code in CSS:

.blog-post {
  margin-bottom: 3rem;
}

.blog-post .large-paragraph {
  font-size: 1.5rem;
}

.blog-post .large-paragraph a {
  text-decoration: underline;
}

.blog-post .large-paragraph a:hover {
  text-decoration: wavy underline;
}

@media (min-width > 1024px) {
  .blog-post .large-paragraph {
    font-size: 2rem;
  }
}
Enter fullscreen mode Exit fullscreen mode

With CSS Nesting, we can nest the children making the code more organized. In a similar fashion to what CSS preprocessors like Sass or Less do:

.blog-post {
  margin-bottom: 3rem;

  .large-paragraph {
    font-size: 1.5rem;

    @media (min-width > 1024px) {
      font-size: 2rem;
    }

    a {
      text-decoration: underline;

      &:hover {
        text-decoration: wavy underline;
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Both ways will translate into the same CSS code for the browser. So there won't be any difference between the two.

Specificity

There will be some differences when calculating the specificity, especially when there is more than one selector in a rule:

article, .blog-post {
  & .large-paragraph {
    font-size: 1.5rem;
  }
}
Enter fullscreen mode Exit fullscreen mode

That code above will be equivalent to the following:

:is(article, .blog-post) .large-paragraph {
  font-size: 1.5rem;
}
Enter fullscreen mode Exit fullscreen mode

Because it is equivalent to an :is(), the larger of the specificities will be used in the &. This may lead to confusion. For example, in the code above, an article with a .large-paragraph will have the same specificity as two classes instead of one class and one element.

Ideally, that won't be a big problem because our CSS will be more modular, and we won't find unpleasant surprises.


As mentioned above, this module is hot, and the specification is constantly updated. When writing this article, the latest draft is less than a month old, and many changes are still coming. So the notation displayed in this article may change. For example, just a few weeks ago, there was a big poll to gather information from developers and decide on the best syntax to move forward (spoiler alert: option 3 won). Also, the @nest at-rule has been dropped in the latest versions of the draft, one reason why it was not mentioned.

I believe this technique will be beneficial for organizing code and avoiding human errors, and I can't wait until it is available in all browsers.

Top comments (21)

Collapse
 
darkwiiplayer profile image
𒎏Wii 🏳️‍⚧️

Would it be too pessimistic to say "Meh, firefox will probably just kill it like every other good thing in the web"?

I'm probably being a bit hard on firefox here, but JFC every single feature I want seems to be waiting for them to finally implement it.

Collapse
 
ivan_jrmc profile image
Ivan Jeremic

You mean Safari

Collapse
 
alvaromontoro profile image
Alvaro Montoro

I ha(v/t)e to admit that Safari has been doing a good job lately. While it is way behind in features and options, some of the latest CSS things pop up on Safari first... which doesn't make much sense, but oh well...

Collapse
 
darkwiiplayer profile image
𒎏Wii 🏳️‍⚧️

Doesn't safari actually still have TCO in its javascript engine, even though firefox unilaterally decided to kill that feature for no reason whatsoever?

Automatically x3 times better if you ask me

Collapse
 
nlxdodge profile image
NLxDoDge

The main reasons I use SCSS/SASS is because of nesting and variables. If they fix those two we are getting closer to not needing to compile everything, that would be huge.

But I have some other things, like functions or using a variable in a function call that I really like to see as well.

Collapse
 
darkwiiplayer profile image
𒎏Wii 🏳️‍⚧️

What do you need variables for that you cannot do with custom properties already?

Collapse
 
nlxdodge profile image
NLxDoDge • Edited

I had some issues with trying to make the border of div transparent but not the element itself (else a opacity filter would have worked).

So instead I wanted to do:

div {
    border-color: argb(#123123, 0.4);
}
Enter fullscreen mode Exit fullscreen mode

But then with a variable instead as I wanted to make a light and dark togglable theme. But I found out that using css variables in this context doesn't work.

:host {
    --test: #213213;
}

div {
    border-color: argb(var(--test), 0.4);
}
Enter fullscreen mode Exit fullscreen mode

Maybe I am doing something wrong (or Firefox doesn't allow this?).

Thread Thread
 
darkwiiplayer profile image
𒎏Wii 🏳️‍⚧️ • Edited

Well, no, that doesn't work, because argb isn't a thing, and if you want to use rgb you'll have to provide R, G and B separately.

What you can do, for example:

:host {
   --theme-hue: 140deg;
   --theme-saturation: 20%;
   --theme-lightness: 10%;
}

div {
   border-color: hsl(
      var(--theme-hue),
      var(--theme-saturation),
      var(--theme-lightness),
      0.4
   );
}
Enter fullscreen mode Exit fullscreen mode

and I'm 90% sure you can combine those three variables into a --theme-hsl variable somehow but cba to test it right now so won't include it in the code.


EDIT: And of course, once CSS Color Module Level 5 becomes a thing, you can just do

my-element {
   --test: #123123;
   border-color: rgb(from var(--test) r g b 0.2);
}
Enter fullscreen mode Exit fullscreen mode
Thread Thread
 
nlxdodge profile image
NLxDoDge

Thanks for your explanation, I don't really do front-end that much (I do Java backend at work) but I never knew you could to things like this. Thanks!

Thread Thread
 
starkraving profile image
Mike Ritchie

argb isn’t a thing as mentioned, but rgba is, which is what you’re writing in the sample code anyways. R G and B go from 0 to 255, and A goes from 0.0 to 1.0

Collapse
 
fruntend profile image
fruntend

Сongratulations 🥳! Your article hit the top posts for the week - dev.to/fruntend/top-10-posts-for-f...
Keep it up 👍

Collapse
 
orix profile image
Waleedh Nihal

Cool makes work much easier 👍🏽!

Collapse
 
ota200 profile image
O.T.A

Css is going to get much easier now, thank you for sharing, can't wait for this feature :)

Collapse
 
bigahuna profile image
Michael Kettel

I was using sass/scss just because it is so much better to have nested css instructions. Love to see this feature becoming a standard...

Collapse
 
anothertobi profile image
Tobi

This is a nightmare. Css should only define styles, not handle logic. Javascript is enough logic to handle already

Collapse
 
alvaromontoro profile image
Alvaro Montoro

How is this logic?

Collapse
 
anothertobi profile image
Tobi

If (thing a is nested in thing b)
Apply style to thing a

Now what if I don't want to use thing b anymore but thing a? Then I have to change the css file, even though that makes no sense at all

Thread Thread
 
alvaromontoro profile image
Alvaro Montoro

That is how it happens right now in CSS when you put two selectors together (even without the nesting):

.car {
  width: 200px;
}

.car .door {
  color: red;
}
Enter fullscreen mode Exit fullscreen mode

Those styles apply to the .door in a .car, but not to a .door inside a .house.

With CSS nesting this will be more evident for the developer:

.car {
  width: 200px;

  .door {
    color: red;
  }
}
Enter fullscreen mode Exit fullscreen mode

It's just syntactic sugar that helps keep the code more organized and clean. The main danger is getting into the curly braces hell.

Thread Thread
 
anothertobi profile image
Tobi

Fair enough. Still I would rather move in a direction where logic is handled in Javascript and css is styling and only styling. Just today I had to debug some complex sass function. That's hell. But of course this is subjective

Thread Thread
 
someofthethings profile image
Peter Carter • Edited

Nesting is not logic in any way that makes the code more difficult to read when used properly and doesn't muddy seperation of concerns in any meaningful way. Once you get really adept at SCSS/Sass you start to be able to nest in ways that are intuitive, elegent and make the code a joy to read and reason about.

If you're having to debug a complex Sass function that's not intuitive, it is 100% not an issue with nesting, and everything to do with the developer not doing stuff properly. If you're struggling here then SonarCloud has some really neat features for helping to organise such code. If it's really bad it'll throw a proper riot-tantrum initially, but if you can find anyone good enough to actually fix issues it flags then you'll see what good nesting does for you.

Collapse
 
darkwiiplayer profile image
𒎏Wii 🏳️‍⚧️ • Edited

@alvaromontoro by the way, thoughts on @scope?