@@ -2828,6 +2828,79 @@ Consume a block's contents</h4>
28282828 append it to |rules|.
28292829 </dl>
28302830
2831+ <details class=note>
2832+ <summary> Implementation note</summary>
2833+
2834+ This spec, as with many CSS specs,
2835+ has been written to prioritize understandability
2836+ over efficiency.
2837+ A number of algorithms,
2838+ notably the above "parse as a declaration, then parse as a rule" behavior
2839+ can be fairly inefficient
2840+ if implemented naively as described.
2841+
2842+ However, the behavior has been carefully written
2843+ to allow "early exits" as much as possible.
2844+ In particular,
2845+ and roughly in order of when the exit can occur:
2846+
2847+ * If the first non-whitespace token
2848+ isn't an <<ident-token>>
2849+ for a recognized property name (or a custom property name),
2850+ you can immediately stop parsing as a declaration
2851+ and reparse as a rule instead.
2852+ If the <em> next</em> non-whitespace token isn't a <<colon-token>> ,
2853+ you can similarly immediately stop parsing as a declaration.
2854+
2855+ (That is, ''font+ ...'' is guaranteed to not be a property,
2856+ nor is <css> not-a-prop-name: ...</css> .)
2857+
2858+ * If the first two non-whitespace tokens
2859+ are a custom property name and a colon,
2860+ it's definitely a custom property
2861+ and won't ever produce a valid rule,
2862+ so even if the custom property ends up invalid
2863+ there's no need to try and reparse as a rule.
2864+
2865+ (That is, ''--foo:hover {...}'' is guaranteed to be a custom property,
2866+ not a rule.)
2867+
2868+ * If the first three non-whitespace tokens
2869+ are a valid property name, a colon, and anything other than a <<{-token>> ,
2870+ and then while parsing the declaration's value you encounter a <<{-token>> ,
2871+ you can immediately stop parsing as a declaration
2872+ and reparse as a rule instead.
2873+
2874+ (That is, ''font:bar {...'' is guaranteed to be an invalid property.)
2875+
2876+ * If you see a recognized property name, a colon, and a {}-block,
2877+ but the first non-whitespace tokens following that block
2878+ isn't either immediately the final semicolon,
2879+ or the !important followed by the semicolon,
2880+ you can immediately stop parsing as a declaration
2881+ and reparse as a rule instead.
2882+
2883+ (That is, ''font: {} bar ...'' is guaranteed to be an invalid property;
2884+ you don't need to keep parsing until you hit a semicolon.)
2885+
2886+ Similarly,
2887+ even tho the parsing requirements are specified
2888+ to rely on checking the grammar of the declarations
2889+ as you parse,
2890+ a <em> generic</em> processor
2891+ trying to implement a non-CSS language
2892+ on top of the generic CSS <em> syntax</em>
2893+ can still get away with just verifying that declarations
2894+ start with an ident, a colon,
2895+ and then either contain solely a {}-block
2896+ or no {}-block at all.
2897+ They'll just spent a little more time on parsing
2898+ than an implementation with grammar knowledge
2899+ in cases like ''foo:hover ... {}'' ,
2900+ since they can't early-exit on the first token.
2901+ </details>
2902+
2903+
28312904
28322905<h4 id="consume-declaration">
28332906Consume a declaration</h4>
@@ -2873,19 +2946,6 @@ Consume a declaration</h4>
28732946 and with <<semicolon-token>> as the stop token,
28742947 and set |decl|'s value to the result.
28752948
2876- If |decl|'s name is a [=custom property name string=] ,
2877- then set |decl|'s |original text|
2878- to the segment of the original source text string
2879- corresponding to the tokens
2880- returned by the [=consume a list of component values=] call.
2881-
2882- If |decl|'s name is an [=ASCII case-insensitive=] match for "unicode-range",
2883- [=consume the value of a unicode-range descriptor=]
2884- from the segment of the original source text string
2885- corresponding to the tokens
2886- returned by the [=consume a list of component values=] call,
2887- and replace |decl|'s value with the result.
2888-
28892949 <li>
28902950 If the last two non-<<whitespace-token>> s in |decl|'s value are
28912951 a <<delim-token>> with the value "!"
@@ -2897,6 +2957,27 @@ Consume a declaration</h4>
28972957 While the last item in |decl|'s value is a <<whitespace-token>> ,
28982958 [=list/remove=] that token.
28992959
2960+ <li>
2961+ If |decl|'s name is a [=custom property name string=] ,
2962+ then set |decl|'s |original text|
2963+ to the segment of the original source text string
2964+ corresponding to the tokens
2965+ of |decl|'s value.
2966+
2967+ Otherwise, if |decl|'s value contains a top-level [=simple block=]
2968+ with an associated token of <<{-token>> ,
2969+ and also contains <em> any other</em> non-<<whitespace-token>> value,
2970+ return nothing.
2971+ (That is, a top-level {}-block is only allowed
2972+ as the entire value of a non-custom property.)
2973+
2974+ Otherwise, if |decl|'s name is an [=ASCII case-insensitive=] match for "unicode-range",
2975+ [=consume the value of a unicode-range descriptor=]
2976+ from the segment of the original source text string
2977+ corresponding to the tokens
2978+ returned by the [=consume a list of component values=] call,
2979+ and replace |decl|'s value with the result.
2980+
29002981 <li>
29012982 If |decl| is valid in the current context,
29022983 return it;
0 commit comments