[csswg-drafts] [css-nesting-1] Relaxed nesting and var() (#9317)

andruud has just created a new issue for https://github.com/w3c/csswg-drafts:

== [css-nesting-1] Relaxed nesting and var() ==
In #7961, we resolved to allow nested style rules that begin with ident-token, and use parser restarts to solve the ambiguity that arose from that.

However, there's a serious problem that we missed: `var()` in standard properties.

```
div {
  width:is(.x1) {
    /* ... */
  }
  width:is(.x2) {
    /* ... */
  }
  /* ... */
  width:is(.xN) {
    /* ... */
  }
}
```

The idea from #7961 is that when standing at `width` `:`, we'll quickly back out of declaration parsing, because the _next_ token (`is(`) does not match `width`'s property grammar. Restarting and trying again as a nested style rule is cheap, because we won't proceed too far into the tokens before discovering that it's not a valid declaration.

However, `var()` interferes with this plan:

```
div {
  width:is(.x1) {
    /* ... */
  }
  width:is(.x2) {
    /* ... */
  }
  /* ... */
  width:is(.xN) {
    /* ... */
  }
  var(--x) /* <====== New */
}
```

Now we have a _valid_ `width` declaration (parse-time) consisting of everything from the first `width` to the end of the `div`-block. The problem is not that `var()` is present, but that it _can_ be present. Even when it's not there, we have to scan the whole rest of the block to check whether it is or not. If it's _not_ there, we have O(N^2) behavior, because we'll consume the whole rest of the block at `width:is(.x1)`, restart as a style rule, and then repeat at `width:is(.x2)`.

Another related problem (from @tabatkins) is the following:

```
div {
  width:focus {
    color: var(--x);
  }
}
```

Per #7961, this is a valid `width` _declaration_, which isn't a great result. Especially since you'd get a rule if you do the same thing minus the `var()`.

We could solve this problem one of the following ways:

 1. Giving up on relaxed nesting completely.
 2. Ban `{}` entirely from declarations. With this we can stop when we see `{`.
 3. Ban `{}` from declarations, unless it's the whole value (from @tabatkins). This is probably also acceptable, because we can look at the first non-whitespace token after `:` and if that's _not_ `{`, then we can stop when we do see `{`. Otherwise we stop after the first `}`.

I would not go any weaker than (3), in particular the previously discussed restriction of "blocks are valid, but only at the end" is not good enough, because authors can realistically put any amount of stuff inside that block (if it's intended as a nested style rule), and also it wouldn't fix the problem illustrated by the last code snippet in this issue.

cc @emilio @mdubet 



Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/9317 using your GitHub account


-- 
Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config

Received on Thursday, 7 September 2023 09:05:12 UTC