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

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

"serious problem" is slightly hyperbolic; these problems only occur if you have a certain class of "ambiguous rules" - rules whose selectors start with a type selector that matches a valid property name, followed by a pseudo-class. *All other rules* early-exit property parsing within the first few tokens, and aren't an issue. These ambiguous rules are, currently and for the forseeable future, essentially unknown in practical CSS. The only overlaps between HTML/SVG/MathML element names and CSS property names are `font` and `marker`, both of which aren't really an issue here. (Custom element names can potentially make this more of an issue; an author could create an `<align-content>` element and try to style it, for example. So it's not something that'll *never* happen, but it'll still be very rare imo.)

Further, the N^2 behavior is only N^2 *in the number of ambiguous rules among a given rule's child rules*. If someone writes 1000 child rules in a single parent rule, and every single one is ambiguous, yeah it's not great. But is that realistically a situation that'll happen in practice? I don't think so.

The "if there *is* a var() we still consume the ambiguous rules as a declaration" one is a little more problematic, yeah. Still gated behind an author writing an ambiguous rule, but if that does happen, then having a var() in the child rules is a very realistic scenario.

So, I don't think this is a *strictly necessary* fix, as in we-can't-ship-if-this-isn't-fixed; this will not actually affect authors in meaningful ways. But it would definitely be *nice* to fix.

-------

So, solutions!

The first solution is indeed weaker than your #3, Anders: we've already accepted a future design constraint on ourselves that *if* we ever included curly blocks in property values, we'll restrict them to the end of the value. This ensures that a browser that doesn't understand the property (and thus fails decl parsing and restarts with rule parsing) will have their parser re-sync with that of a newer browser virtually immediately; they'll consume tokens up to the block, throw it away as an invalid rule, then try to consume the `;`, throw *it* away too, then it's re-synced.

So, we could make that design constraint an official syntax constraint: outside of custom properties (which will continue to allow anything), curly blocks can only appear at the end of declarations. We then make this restriction have the ability to cause a var()-containing property to fail at parse time.

With this, an ambiguous rule will first parse as a decl, getting through the entire {} block. Then it will keep parsing to try and find the `;` or the `!important` or the end of the parent block (since it knows {} is only valid at the end of the property); when it instead runs into the start of the next selector, it'll know this is an invalid property and restart with the rule parser.

This solves both problems *reasonably* well.  The N^2 behavior goes away entirely; instead you just pay parsing costs twice per ambiguous rule, which is what you'll already do for invalid properties. The only remaining downside is that ambiguous rules don't let us early-exit the property parser; we will still end up sucking down the entire rule, which might be big, before we finally hit the end and are allowed to fail and retry with rule parsing. The "ambiguous child rule contains a var(), which forces us to consider it a valid declaration" problem also mostly goes away; it'll only still occur if the ambiguous rule is the final thing in the parent rule.

-------

But I think your #3 possibility is also just fine. We have zero plans to allow curly blocks in properties at all right now; the only suggestions for doing so have been to allow something like inlining a bunch of longhands into a shorthand. So, slightly widening our design prohibition from "must be last in the value" to "must be the entire value" does not preclude *literally anything that's ever been suggested*, afaik. And then, yeah, you get even better behavior, since a valid property with a curly in it will always start like `foo: {`, and that is *by definition* not a valid selector for a block, so that breaks the ambiguity both entirely and immediately. 

This avoids the remaining downsides of my above suggestion: you can *always* early-exit from the declaration parser when you're actually given a rule (at most, you'll just consume the entire selector and then abort when you see the `{`, which is pretty short); and it works equally well whether there's any additional rules following the ambiguous rule or not.

I would be completely okay with this, it's just a slight expansion from what the WG had already accepted as a future design restriction.

(Notably, this is essentially how Sass avoids the issue - it just assumes that properties can't validly contain curly blocks, and bails on declaration parsing if it encounters one.)

-------

> I thought banning { from declarations whole-sale wasn't acceptable because people put json like things in their custom properties? But I might be mis-remembering.

Right, custom properties would still be able to include whatever. Like we explored in the Nesting discussion, custom props are not valid custom element names, so the chance of them showing up as an ambiguous rule is essentially nil.

> Not sure how this ended up actually being specified, but one possibility we discussed was to simply fail style rule parsing for anything that starts with a dashed ident.

Yes, that's how it's specified, see <https://drafts.csswg.org/css-syntax/#consume-a-qualified-rule>. If you are trying to parse a rule and the first two significant tokens you see are a dashed ident followed by a colon, you immediately consume the remnants of a bad declaration and don't return anything. (But most of the time you won't even hit this; very few things can cause a custom property be fail declaration parsing so they'll almost never fall back to being parsed as a rule.)

-- 
GitHub Notification of comment by tabatkins
Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/9317#issuecomment-1710831586 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 22:16:17 UTC