@@ -2828,6 +2828,79 @@ Consume a block's contents</h4>
2828
2828
append it to |rules|.
2829
2829
</dl>
2830
2830
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
+
2831
2904
2832
2905
<h4 id="consume-declaration">
2833
2906
Consume a declaration</h4>
@@ -2873,19 +2946,6 @@ Consume a declaration</h4>
2873
2946
and with <<semicolon-token>> as the stop token,
2874
2947
and set |decl|'s value to the result.
2875
2948
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
-
2889
2949
<li>
2890
2950
If the last two non-<<whitespace-token>> s in |decl|'s value are
2891
2951
a <<delim-token>> with the value "!"
@@ -2897,6 +2957,27 @@ Consume a declaration</h4>
2897
2957
While the last item in |decl|'s value is a <<whitespace-token>> ,
2898
2958
[=list/remove=] that token.
2899
2959
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
+
2900
2981
<li>
2901
2982
If |decl| is valid in the current context,
2902
2983
return it;
0 commit comments