Skip to content

Commit 02db7b2

Browse files
committed
[css-nesting-1] Apply #8662, so &div is invalid and div& is valid.
1 parent 2e5cbb5 commit 02db7b2

File tree

1 file changed

+31
-128
lines changed

1 file changed

+31
-128
lines changed

css-nesting-1/Overview.bs

+31-128
Original file line numberDiff line numberDiff line change
@@ -104,10 +104,9 @@ Nesting Style Rules {#nesting}
104104
possibly multiple times.
105105

106106
A [=nested style rule=] is exactly like a normal style rule,
107-
with the exception that its [=selector=]
108-
cannot start with an [=identifier=] or [=functional notation=].
109-
Additionally, [=nested style rules=]
110-
can use [=relative selectors=].
107+
except that it can use can use [=relative selectors=],
108+
which are implicitly relative
109+
to the elements matched by the parent rule.
111110

112111
<div class=example>
113112
That is,
@@ -117,7 +116,7 @@ Nesting Style Rules {#nesting}
117116
.foo {
118117
color: red;
119118

120-
.bar {
119+
a {
121120
color: blue;
122121
}
123122
}
@@ -130,7 +129,7 @@ Nesting Style Rules {#nesting}
130129
.foo {
131130
color: red;
132131
}
133-
.foo .bar {
132+
.foo a {
134133
color: blue;
135134
}
136135
</pre>
@@ -171,72 +170,6 @@ Nesting Style Rules {#nesting}
171170
</pre>
172171
</div>
173172

174-
<div class=example>
175-
However, starting the nested selector with an identifier
176-
(a [=type selector=], in other words)
177-
is invalid:
178-
179-
<pre class="lang-css invalid">
180-
div {
181-
color: red;
182-
183-
input {
184-
margin: 1em;
185-
}
186-
}
187-
/* Invalid, because "input" is an identifier. */
188-
</pre>
189-
190-
Such selectors can still be written,
191-
they just need to be slightly rephrased:
192-
193-
<pre class=lang-css>
194-
div {
195-
color: red;
196-
197-
& input { margin: 1em; }
198-
/* valid, no longer starts with an identifier */
199-
200-
:is(input) { margin: 1em; }
201-
/* valid, starts with a colon,
202-
and equivalent to the previous rule. */
203-
}
204-
</pre>
205-
</div>
206-
207-
<details class=note>
208-
<summary>Why are there restrictions on nested rule selectors?</summary>
209-
210-
Nesting style rules naively inside of other style rules is, unfortunately, ambiguous--
211-
the syntax of a selector overlaps with the syntax of a declaration,
212-
so an implementation requires unbounded lookahead
213-
to tell whether a given bit of text is a declaration or the start of a style rule.
214-
215-
For example, if a parser starts by seeing ''color:hover ...'',
216-
it can't tell whether that's the 'color' property
217-
(being set to an invalid value...)
218-
or a selector for a <code>&lt;color></code> element.
219-
It can't even rely on looking for valid properties to tell the difference;
220-
this would cause parsing to depend on which properties the implementation supported,
221-
and could change over time.
222-
223-
Forbidding nested style rules from starting with an [=identifier=]
224-
works around this problem--
225-
all [=declarations=] start with an identifier
226-
giving the property name,
227-
so the parser can immediately tell whether it's parsing a [=declaration=] or [=style rule=].
228-
229-
Some non-browser implementations of nested rules do not impose this requirement.
230-
It <em>is</em>, in most cases, <em>eventually</em> possible
231-
to tell properties and selectors apart,
232-
but doing so requires unbounded lookahead in the parser;
233-
that is, the parser might have to hold onto an unknown amount of content
234-
before it can tell which way it's supposed to be interpreting it.
235-
CSS to date requires only a small, known amount of lookahead in its parsing,
236-
which allows for more efficient parsing algorithms,
237-
so unbounded lookahead is generally considered unacceptable among browser implementations of CSS.
238-
</details>
239-
240173

241174
<!--
242175
██████ ██ ██ ██ ██ ████████ ███ ██ ██
@@ -259,9 +192,6 @@ Syntax {#syntax}
259192
[=Nested style rules=] differ from non-nested rules
260193
in the following ways:
261194

262-
* The selector of [=nested style rules=]
263-
must not start with an [=identifier=]
264-
or a [=functional notation=].
265195
* A [=nested style rule=] accepts a <<relative-selector-list>>
266196
as its prelude
267197
(rather than just a <<selector-list>>).
@@ -275,9 +205,6 @@ Syntax {#syntax}
275205
The precise details of how nested style rules are parsed
276206
are defined in [[!CSS-SYNTAX-3]].
277207

278-
ISSUE(7961): The CSSWG is currently exploring the consequences of parsing lookahead,
279-
and may adjust the allowed syntax as a result.
280-
281208
An invalid [=nested style rule=] is ignored,
282209
along with its contents,
283210
but does not invalidate its parent rule.
@@ -438,10 +365,10 @@ Syntax {#syntax}
438365

439366
<b>/* Example usage with Cascade Layers */</b>
440367
@layer base {
441-
html {
368+
html {
442369
block-size: 100%;
443370

444-
& body {
371+
body {
445372
min-block-size: 100%;
446373
}
447374
}
@@ -459,7 +386,7 @@ Syntax {#syntax}
459386
block-size: 100%;
460387

461388
@layer support {
462-
& body {
389+
body {
463390
min-block-size: 100%;
464391
}
465392
}
@@ -511,18 +438,6 @@ Syntax {#syntax}
511438
}
512439
*/
513440
</pre>
514-
515-
But these are not valid:
516-
517-
<pre class=lang-css>
518-
<b>/* Selector starts with an identifier */</b>
519-
.foo {
520-
color: blue;
521-
div {
522-
color: red;
523-
}
524-
}
525-
</pre>
526441
</div>
527442

528443
<div class=note>
@@ -541,34 +456,25 @@ Syntax {#syntax}
541456

542457
<pre class="lang-css">
543458
.foo {
544-
color: blue;
545-
&Bar { color: red; }
459+
color: blue;
460+
&Bar { color: red; }
546461
}
547462
/* In Sass, this is equivalent to
548-
.foo { color: blue; }
549-
.fooBar { color: red; }
463+
.foo { color: blue; }
464+
.fooBar { color: red; }
550465
*/
551466
</pre>
552467

553-
Unfortunately, this string-based interpretation is ambiguous with
554-
the author attempting to add a type selector in the nested rule.
555-
''Bar'', for example,
556-
<em>is</em> a valid <a href="https://html.spec.whatwg.org/multipage/custom-elements.html">custom element name</a> in HTML.
468+
This is not allowed in CSS,
469+
as nesting is not a syntax transformation,
470+
but rather matches on the actual elements the parent selector matches.
557471

558-
CSS doesn't do this:
559-
the nested selector components are interpreted atomically,
560-
and not string-concatenated:
561-
562-
<pre class="lang-css">
563-
.foo {
564-
color: blue;
565-
&Bar { color: red; }
566-
}
567-
/* In CSS, this is instead equivalent to
568-
.foo { color: blue; }
569-
Bar.foo { color: red; }
570-
*/
571-
</pre>
472+
It is also true that the selector ''&Bar'' is invalid in CSS in the first place,
473+
as the ''Bar'' part is a type selector,
474+
which must come first in the compound selector.
475+
(That is, it must be written as ''Bar&''.)
476+
So, luckily, there is no overlap between CSS Nesting
477+
and the preprocessor syntax.
572478
</div>
573479

574480
<div algorithm>
@@ -912,6 +818,10 @@ Mixing Nesting Rules and Declarations {#mixing}
912818
before "Order Of Appearance" comes into consideration.
913819
</div>
914820

821+
Note: This behavior both matches many existing preprocessor-based nesting behaviors,
822+
and ensures that a rule can be faithfully expressed in the CSSOM
823+
without requiring drastic changes to the existing {{CSSStyleRule}} object.
824+
915825
Note: While one <em>can</em> freely intermix declarations and nested rules,
916826
it's harder to read and somewhat confusing to do so,
917827
since all the properties <em>act as if</em> they came before all the rules.
@@ -1133,19 +1043,12 @@ Nesting Selector: the ''&'' selector {#nest-selector}
11331043
The [=nesting selector=] is capable of matching [=featureless=] elements,
11341044
if they were matched by the parent rule.
11351045

1136-
The <a>nesting selector</a> is allowed anywhere in a <a>compound selector</a>,
1137-
even before a <a>type selector</a>,
1138-
violating the normal restrictions on ordering within a <a>compound selector</a>.
1139-
1140-
<div class='example'>
1141-
For example, ''&div'' is a valid nesting selector,
1142-
meaning "whatever the parent rules matches,
1143-
but only if it's also a <{div}> element".
1144-
1145-
It could also be written as ''div&'' with the same meaning,
1146-
but that wouldn't be valid to start a [=nested style rule=]
1147-
(but it could be used somewhere other than the very start of the selector).
1148-
</div>
1046+
While the position of a [=nesting selector=] in a [=compound selector=]
1047+
does not make a difference in its behavior
1048+
(that is, ''&.foo'' and ''.foo&'' match the same elements),
1049+
the existing rule that a [=type selector=], if present, must be first in the [=compound selector=]
1050+
continues to apply
1051+
(that is, ''&div'' is illegal, and must be written ''div&'' instead).
11491052

11501053

11511054
<!--

0 commit comments

Comments
 (0)