back
180 comments
> Back in December, we wrote an article detailing three different options for CSS Nesting.

> Web developers responded to the poll with great clarity. Option 3 won in a landslide.

Yup, pretty much. The only thing I really wish won however was making the beginning "&" always required for nesting. Instead you're able to omit it if there's any other symbol. Example from article:

  main {
   .bar { ... }
   #baz { ...}
   :has(p) { ... }
   ::backdrop { ... }
   [lang|="zh"] { ... }
   \* { ... }
   + article { ... }
   > p { ... }
   ~ main { ... }
  }
The position of requiring & was not represented in the poll but seemed really popular in all the comments and seems like it would only make the parser's job easier (both now and in the future of CSS)

Regardless I'm just happy it's finally here! Hard to see the use-cases for sass in 2024 but, like jQuery, it's definitely made its mark on the history of the development of web standards

Relevant links on this:

https://twitter.com/LeaVerou/status/1580215877705687040, a poll about this specific matter (with links to other relevant polls which on the surface contradict this one).

https://github.com/w3c/csswg-drafts/issues/7834#issuecomment..., on this exact matter (chosen as a convenient starting point, after matters were already settled, but the whole issue is about it). By the time this poll was done, they had already decided not to consider mandatory-&, though I don’t really understand why (it’s pretty obvious to me that dividing into 3a and 3b would have been much more interesting than a couple of the other options which were straw men that no one was capable of taking seriously even if they tried).

https://github.com/w3c/csswg-drafts/issues/7961, about doing away with & in all cases for descendant selector (… which would be terrible for complexity and worst-case performance, and is only being considered because they already made things inconsistent by making & optional in every other case).

(I don’t like where it’s ended up, and consider requiring the & in all cases to be obviously materially superior, for both machine and human handling, and that there’s clear concrete advantage in having the requirement as an actual language rule rather than only a linter-enforced choice. People are far too hung up on exactly Sass syntax.)

> it would only make the parser's job easier

Mind you, it’s not a big difference; it’s just “if there’s no & in the selector, insert one and a descendant combinator at the start” in some shape, which could be as little as half a dozen lines of code net.

I remember the main argument against this is that you can always enforce this with a linter and either way it's not a slower parser, maybe slightly more complex.

Personally I do agree and I like the explicitness of always having the &

> Hard to see the use-cases for sass in 2024

Possibly mixins, loops, and variables, which, unlike CSS variables, can be used in media queries.

> Hard to see the use-cases for sass in 2024

Modules make writing CSS much less of a naming game. Anything you can do to reduce one of the 2 hardest problems in CS is worth it.

> Web developers responded to the poll with great clarity. Option 3 won in a landslide.

Because there was no “none of the above” option, which developers asked for.

One thing worth noting is that & substitutes for `:is(...)` in spirit under the hood, which means there are some significant behavior differences between native CSS nesting and Sass.

Here's one:

  .foo .bar {
    .baz & {
      color: red;
    }
  }

In Sass, that would compile to:

  .baz .foo .bar {
    color: red;
  }
With native nesting, it effectively compiles to:

  .baz :is(.foo .bar) {
    color: red;
  }
The Sass version matches this DOM structure:

  <div class="baz">
    <div class="foo">
      <div class="bar">
        ...
But the native version matches all of these structures:

  <div class="baz">
    <div class="foo">
      <div class="bar">
        ...
  
  <div class="foo">
    <div class="baz">
      <div class="bar">
        ...

  <div class="foo baz">
    <div class="bar">
      ...
Not a criticism at all (the `:is(...)` behavior is a very useful and welcome enhancement to CSS) but a notable difference worth understanding coming from Sass.
I’ll criticize it.

I recognize this is a preview and I desperately hope this implementation isn’t kept around and treated as a quirk.

This implementation is extremely unintuitive given their explanation of the expected behavior of CSS Nesting and the & symbol.

To quote:

    The & signals to the browser “this is where I want the selector from outside this nest to go”.
Their explanation and the actual implementation result in a majorly different CSS selector.

The implemented functionality, however useful, makes no sense as a default if one can explicitly use :is to achieve this behavior like below.

    .foo .bar {
        .baz :is(&) {
        }
    }
The default should behave like they claim it does; simply replace & with the “outside” selector.
Notably, this is identical to the behavior you get from @scope's nesting, and from passing a complex selector to an `el.querySelector()`.

(We discussed adopting Sass's behavior in <https://github.com/w3c/csswg-drafts/issues/8310#issuecomment...> but ultimately dropped it.)

Agree important to note the difference but I personally prefer the nested CSS behavior. Much more sensible to use `&` as a logical operator
Nested rules is just a syntax sugar.

In Sciter, 10 years ago, I came up with style sets:

    @set Main {
      :root { ... } // root element that has this set applied 
      .bar { ... } 
      article { ... } 
      :root > article { ... } 
    }

    main { style-set: Main; } // main element with the set applied 
This solution solves two problems:

1. Modular/componentized style definition - same goal as in nesting styles, but without introduction of new syntax constructs.

2. Reduces CSS resolution load. Rules inside the set are scanned only for DOM children that have style set defined.

3. DOM element may have @styleset="url#name" attribute defined - used in components (Web alike components and React alike components)

If syntactic sugar was really just sugar, JS would have sticked to callback functions, and we’d still be inventing abstractions to make our lives easier.

Syntactic sugar, sometimes, is the promise of sunnier mornings and that matters.

Maybe I am an outlier... but I really don't like nested style documents like those founds with SASS, LESS, PostCSS. When the number of nested selectors becomes too great it can become very difficult to reason about. I would never use this without some kind of lint rule enforcing a maximum depth of selector nesting. I agree with the other commenters ITT taking the position flat CSS looks cleaner than nested documents.
This is great! The only reason I use SCSS is for the nesting. It should have been implemented 10 years ago, but better late then never.
Awesome to finally have nesting. The way I see it, this took 10 years longer than it should have.

I feel the only big thing missing from the vanilla stack for me right now is a template element that multiple html files can share. Just like how you make a blog header in Jekyll or Hugo and it adds it on all your blog posts get the header. I haven't found an easy way of doing that if I have a bunch of html pages.

Not implemented in Firefox yet, but they like it: https://github.com/mozilla/standards-positions/issues/695

They're tracking work in https://bugzilla.mozilla.org/show_bug.cgi?id=1648037

Will nested CSS support mixing properties and nested rules in any order, or do all the nested rules have to grouped together at the end? Right now, I frequently write SCSS rules like this:

  .some-class {
      background: blue;
      &:hover {background: red}
      border: 1px solid;
      &:active {border: 1px dashed}
      padding: 16px;

      display: flex;
      gap: 8px;
      
      & > * {
          color: red;
      }
  }
And it would be a pity if that wasn't allowed.

The reason I ask is because I seem to remember an early proposal not allowing this, but I can't find where I read it.

"CSS Nesting will work just like Sass, but with one new rule: you must make sure the nested selector always starts with a symbol."

I think I like it. In general I like the adoption of good features like this. But. It's getting awfully hard to keep track of CSS vs SASS syntax. Starting a greenfield project today I'd leave SASS out of it... but I'm usually working on projects where SASS is already present. Shrug.

https://caniuse.com/css-nesting

So it's the latest chrome, Safari technical preview, and edge behind a flag. No disposition from Firefox yet afaict.

Can someone explain why parsers can't handle nested selectors which don't start with a symbol?

I've written plenty of parsers (recursive descent, packrat, Pratt, and using generators) and not a single one would have any trouble parsing something like:

    html {
      body:has(p) {
        width: 1000px;
      }
    }
The only thing I can think of is that they are trying to avoid a lookahead, i.e. you have selectors like "body:has(p) {" which initially look like they could be setting a "body" attribute to the value "has" until you reach the "(". But these lookaheads aren't hard to implement in practice. There are performance issues if the lookahead has to go too deep, but CSS developers can use the & in those cases as an optimization, and you could limit lookahead depth to something like 256 (which would handle the vast majority of non-malicious use cases).

Perhaps the lookahead has a lot more drastic effect than I'm expecting on performance for short lookaheads, but I'd like to at least see some profiling of that, as it seems to me like this possibility was discarded without much consideration or explanation (it wasn't even included in the poll).

There's also another way to do this without lookaheads at all, by building up a structure for each potential path and then discarding the one that doesn't complete (I think this is basically a DFA but it's been a while since I read literature on this so I'm forgetting the terminology). This would probably avoid the performance issues but also probably be a larger departure from the current implementation of the parsers.

Whenever I see nested CSS, I always think the non-nested version is cleaner.

Then again, I'm lucky enough to often work with my own 'hand-crafted', semantic html, and not some div soup generated by a tool.

This won’t kill Sass/scss. Compilers will still be useful for many reasons, I see those compilers targeting new standards instead. Also, bummer that nested rules made it but <style scoped> was removed. The only viable option for me today to keep a maintainable css code base is to use a css in js solution and a compiler. In fact I don’t see why all this excitement for native features, if all you need could be just a capable compiler(bundling, minification, optimization, dead code elimination etc.)
Sanity has prevailed! Great work from the WebKit team, leading the way here. Not to mention great solve on the `color: blue` fiasco. Balances an edge-case compromise nicely, and leaves it open to future improvements. Bravo.
Related:

Help choose the syntax for CSS Nesting - https://news.ycombinator.com/item?id=34006622 - Dec 2022 (159 comments)

Updated CSS Nesting Syntax to Avoid Common Copy-and-Paste Errors - https://news.ycombinator.com/item?id=33537539 - Nov 2022 (1 comment)

CSS Nesting - https://news.ycombinator.com/item?id=33424361 - Nov 2022 (2 comments)

Help pick a syntax for CSS nesting - https://news.ycombinator.com/item?id=32248419 - July 2022 (240 comments)

CSS Nesting Module - https://news.ycombinator.com/item?id=28375596 - Sept 2021 (71 comments)

CSS Nesting Module - W3C Editor’s Draft - https://news.ycombinator.com/item?id=27684332 - June 2021 (1 comment)

You Probably Shouldn't Be Nesting Your CSS - https://news.ycombinator.com/item?id=6583109 - Oct 2013 (1 comment)

WebKit to get CSS variables, mixins, nesting? - https://news.ycombinator.com/item?id=2111510 - Jan 2011 (6 comments)

man I can't wait to not need LESS/SCSS anymore. the less I need to compile/transpile before handing stuff off to the browser, the better in my book.
I don't know anything about WebKit development processes or community management, so please forgive me if I say something wrong.

Isn't it interesting how the engine has been implementing new features and generally running on a lot of steam coincidentally since the EU's Digital Markets Act (which will force other web engines on iOS) went into effect?

Or maybe the dev process and community interactions has always been like this, in which case disregard what I just said and feel free to correct me.

That's a valuable addition, but it's unfortunate that it arrived late. These days, functional CSS http://minid.net/2019/04/07/the-css-utilitarian-methodology/ is gaining popularity due to its effectiveness in reducing the need for excessive nesting of classes and unwieldy CSS files.
Is there a PostCSS or similar plugin which enforces this nesting syntax (& required for element selectors) so we can be ready for when this is widely adopted?
I am not a big fan of nesting. I have yet to see a codebase where nesting makes CSS more readable. Even with BEM, I find it easier to reason about (and debug) the vanilla style. However, I must admit that `&:hover{}` does have a certain appeal. Also, I am very happy that nesting can be done without tooling in the future. It's a feature that many people love.
This is an excellent step forward for css, and frankly it's nice to see safari take the lead for a change rather than lag behind.

It'll be about a year or so before I'm comfortable using it in production code (assuming it comes to Firefox soon, and presuming it'll get into Edge by default.)

But a year goes past quickly these days, and at least the clock has started ticking.

I am supportive of this. Ofc, parent selector would still be nice, but I understand the problems solving that performantly.

As a highlight, Nested CSS doesn't support nested selectors if they both begin with letters, so the "&" is used as divider.

I highly recommend web-dev's check out the last section of the article*: https://webkit.org/blog/13813/try-css-nesting-today-in-safar...

[*: even though, IMO, in this instance it seems like a hack; nesting CSS styles, while the HTML is nested in the opposite direction seems pretty counterintuitive. but having the tool in your toolbox could be useful for other things.]

    :is(article) &
That looks hacky at best.

The excuse of parsing performance is responsible for so much weird syntax in web standards today. The standards are literally being dragged around by browser vendors' priorities.

I wish they would do it the other way around for once: come up with the cleanest, easiest-for-humans syntax as possible, and tell browser vendors to fix their damn engines. Perhaps this will lead to the development of a new CSS engine that's actually optimized for the latest goodies.

Instead, for the last decade or so, we've only been getting bits and pieces of half-assed imitations of Sass. Better than nothing, of course, but still seriously lacking.

The leading "&" should be required.

All of these questions and quandaries only exist because the "&" is optional. If it were simply required, there would be no ambiguity to humans or to parsers.

> Because of limitations in browser parsing engines...

I'm happy about this feature, but they don't really elaborate on what these "limitations" are, except a passing reference later on to "making the parsing engine slower".

Anyone know what the issue is exactly? Why can't they implement it the other way without making the parsing engine slower?

WebKit is on fire lately, awesome.

We only need an autoupdate feature for Safari. Badly. It’s the only not evergreen big browser, to my knowledge.

Another benefit I'm not seeing is that sass/less/minifiers can now target this new native nesting for the output, which would reduce the overall byte size of the output.

So you don't need to use nesting in your code if you don't want to, but can still take advantage for smaller minified css files using a transpiler.

This syntax matches the CSS Working Group's recommendations, is that correct?

> "starting the nested selector with an identifier is invalid"

https://www.w3.org/TR/css-nesting-1/#example-34e8e94f

I'm losing track of what CSS can do.

Do we have inheritance already?

Pseudocode of what I mean:

    .info {
        font-size: 8px;
    }

    .news extends .info {
        color: black;
    }
So news are displayed in an 8px black font.
This half assed version of nesting is lame, as are all the others. Just give us SCSS its been ten years now, pave the cowpath.
Put it in my veins!!!! Finally!
I wonder if any editor (vscode or plugin) support nested search soon...
What would this mean for the type of website designs we could see?
Css is one hell of a spaghetti mess, why need nested css?
Better late than never :)

Very happy to see something major like this being adopted.

"Everyone wishes CSS nesting could use the same kind of simple syntax that Sass does. That’s impossible"

Oh man... let the asteroid come.

So they dropped "@nest"?
Couldn’t `this` just be a reserved keyword instead of `&`? All these symbols, CSS has become so Perly.
option 3 really was the best option
It's great it's here, but isn't everyone and their dog who wants features like this using PostCSS, LESS or SASS? In a build environment that nearly makes this transparent.

I use Vite and PostCSS and a bevy of linters, image processing tools, even for CSS-only projects because they're so fast and generally so good at what they do that it'd be silly not to. I used to hodge tools together with Makefiles but Vite in particular has made the setup for all this stupid-simple.

I make changes, 100ms later Vite deposits a new, optimised build into my Django static dir.