Skip to content

Commit 77e9601

Browse files
committed
[css-syntax-3] Per WG resolution, {} blocks are only allowed as the entire value of a property. #9317
1 parent 776b5a0 commit 77e9601

File tree

1 file changed

+94
-13
lines changed

1 file changed

+94
-13
lines changed

css-syntax-3/Overview.bs

Lines changed: 94 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -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">
28332906
Consume 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

Comments
 (0)