@@ -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> <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