@@ -104,10 +104,9 @@ Nesting Style Rules {#nesting}
104
104
possibly multiple times.
105
105
106
106
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.
111
110
112
111
<div class=example>
113
112
That is,
@@ -117,7 +116,7 @@ Nesting Style Rules {#nesting}
117
116
.foo {
118
117
color: red;
119
118
120
- .bar {
119
+ a {
121
120
color: blue;
122
121
}
123
122
}
@@ -130,7 +129,7 @@ Nesting Style Rules {#nesting}
130
129
.foo {
131
130
color: red;
132
131
}
133
- .foo .bar {
132
+ .foo a {
134
133
color: blue;
135
134
}
136
135
</pre>
@@ -171,72 +170,6 @@ Nesting Style Rules {#nesting}
171
170
</pre>
172
171
</div>
173
172
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
-
240
173
241
174
<!--
242
175
██████ ██ ██ ██ ██ ████████ ███ ██ ██
@@ -259,9 +192,6 @@ Syntax {#syntax}
259
192
[=Nested style rules=] differ from non-nested rules
260
193
in the following ways:
261
194
262
- * The selector of [=nested style rules=]
263
- must not start with an [=identifier=]
264
- or a [=functional notation=] .
265
195
* A [=nested style rule=] accepts a <<relative-selector-list>>
266
196
as its prelude
267
197
(rather than just a <<selector-list>> ).
@@ -275,9 +205,6 @@ Syntax {#syntax}
275
205
The precise details of how nested style rules are parsed
276
206
are defined in [[!CSS-SYNTAX-3]] .
277
207
278
- ISSUE(7961): The CSSWG is currently exploring the consequences of parsing lookahead,
279
- and may adjust the allowed syntax as a result.
280
-
281
208
An invalid [=nested style rule=] is ignored,
282
209
along with its contents,
283
210
but does not invalidate its parent rule.
@@ -438,10 +365,10 @@ Syntax {#syntax}
438
365
439
366
<b> /* Example usage with Cascade Layers */</b>
440
367
@layer base {
441
- html {
368
+ html {
442
369
block-size: 100%;
443
370
444
- & body {
371
+ body {
445
372
min-block-size: 100%;
446
373
}
447
374
}
@@ -459,7 +386,7 @@ Syntax {#syntax}
459
386
block-size: 100%;
460
387
461
388
@layer support {
462
- & body {
389
+ body {
463
390
min-block-size: 100%;
464
391
}
465
392
}
@@ -511,18 +438,6 @@ Syntax {#syntax}
511
438
}
512
439
*/
513
440
</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>
526
441
</div>
527
442
528
443
<div class=note>
@@ -541,34 +456,25 @@ Syntax {#syntax}
541
456
542
457
<pre class="lang-css">
543
458
.foo {
544
- color: blue;
545
- &Bar { color: red; }
459
+ color: blue;
460
+ &Bar { color: red; }
546
461
}
547
462
/* In Sass, this is equivalent to
548
- .foo { color: blue; }
549
- .fooBar { color: red; }
463
+ .foo { color: blue; }
464
+ .fooBar { color: red; }
550
465
*/
551
466
</pre>
552
467
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.
557
471
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.
572
478
</div>
573
479
574
480
<div algorithm>
@@ -912,6 +818,10 @@ Mixing Nesting Rules and Declarations {#mixing}
912
818
before "Order Of Appearance" comes into consideration.
913
819
</div>
914
820
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
+
915
825
Note: While one <em> can</em> freely intermix declarations and nested rules,
916
826
it's harder to read and somewhat confusing to do so,
917
827
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}
1133
1043
The [=nesting selector=] is capable of matching [=featureless=] elements,
1134
1044
if they were matched by the parent rule.
1135
1045
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).
1149
1052
1150
1053
1151
1054
<!--
0 commit comments