Skip to content

Commit cd35453

Browse files
committed
[css-nesting] Retire @nest, introduce the 'nested declarations rule'
Resolves w3c#10234.
1 parent a533ab9 commit cd35453

File tree

3 files changed

+66
-129
lines changed

3 files changed

+66
-129
lines changed

css-nesting-1/Overview.bs

+50-124
Original file line numberDiff line numberDiff line change
@@ -636,7 +636,7 @@ Nesting Other At-Rules {#conditionals}
636636
with their [=nesting selector=] taking its definition
637637
from the nearest ancestor [=style rule=].
638638
* Properties can be directly used,
639-
acting as if they were nested in an ''@nest'' rule.
639+
acting as if they were nested in a [=nested declarations rule=].
640640

641641
<div class=note>
642642
Specifically, these rules are capable of being [=nested group rules=]:
@@ -667,11 +667,10 @@ Nesting Other At-Rules {#conditionals}
667667
/* equivalent to: */
668668
.foo {
669669
display: grid;
670-
671-
@media (orientation: landscape) {
672-
@nest {
673-
grid-auto-flow: column;
674-
}
670+
}
671+
@media (orientation: landscape) {
672+
.foo {
673+
grid-auto-flow: column
675674
}
676675
}
677676

@@ -754,46 +753,9 @@ Nesting Other At-Rules {#conditionals}
754753
</div>
755754

756755
Runs of consecutive directly-nested properties
757-
are automatically wrapped in ''@nest'' rules.
756+
are automatically wrapped in [=nested declarations rules=].
758757
(This is observable in the CSSOM.)
759758

760-
<div class=example>
761-
762-
For example, the earlier example:
763-
764-
<pre highlight=css>
765-
.foo {
766-
display: grid;
767-
768-
@media (orientation: landscape) {
769-
grid-auto-flow: column;
770-
}
771-
}
772-
/* equivalent to */
773-
.foo {
774-
display: grid;
775-
776-
@media (orientation: landscape) {
777-
@nest {
778-
grid-auto-flow: column;
779-
}
780-
}
781-
}
782-
</pre>
783-
784-
is in fact <em>exactly</em> equivalent,
785-
producing the exact same CSSOM structure.
786-
The {{CSSMediaRule}} object
787-
will have a single {{CSSNestRule}} object
788-
in its <code highlight=js>.childRules</code> attribute,
789-
containing the 'grid-auto-flow' property.
790-
</div>
791-
792-
Note: This does mean that the serialization of such rules will differ
793-
from how they were originally written,
794-
with <em>no</em> directly-nested properties in the serialization.
795-
796-
797759
<h4 id=nesting-at-scope>
798760
Nested ''@scope'' Rules</h4>
799761

@@ -852,7 +814,7 @@ Mixing Nesting Rules and Declarations {#mixing}
852814
and [=nested style rules=] or [=nested group rules=],
853815
all three can be arbitrarily mixed.
854816
Declarations coming after or between rules
855-
are implicitly wrapped in ''@nest'' rules,
817+
are implicitly wrapped in [=nested declarations rules=],
856818
to preserve their order relative to the other rules.
857819

858820
<div class=example>
@@ -867,18 +829,14 @@ Mixing Nesting Rules and Declarations {#mixing}
867829
}
868830

869831
/* equivalent to */
870-
article {
871-
color: green;
872-
& { color: blue; }
873-
@nest { color: red; }
874-
}
832+
article { color: green; }
833+
:is(article) { color: blue; }
834+
article { color: red; }
875835

876836
/* NOT equivalent to */
877-
article {
878-
color: green;
879-
color: red;
880-
& { color: blue; }
881-
}
837+
article { color: green; }
838+
article { color: red; }
839+
:is(article) { color: blue; }
882840
</pre>
883841
</div>
884842

@@ -917,7 +875,7 @@ Mixing Nesting Rules and Declarations {#mixing}
917875

918876
Note: While one <em>can</em> freely intermix declarations and nested rules,
919877
it's harder to read and somewhat confusing to do so,
920-
since the later properties are automatically wrapped in an ''@nest'' rule
878+
since the later properties are automatically wrapped in a [=nested declarations rule=]
921879
that doesn't appear in the source text.
922880
For readability's sake,
923881
it's recommended that authors put all their properties first in a style rule,
@@ -1139,19 +1097,19 @@ Nesting Selector: the ''&'' selector {#nest-selector}
11391097
(that is, ''&div'' is illegal, and must be written ''div&'' instead).
11401098

11411099

1142-
<!-- Big Text: @nest
1100+
<!-- Big Text: Nested Decl
11431101

1144-
███▌ █▌ █████▌ ███▌ █████▌
1145-
█▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌
1146-
▌▐█ █▌ █▌ █▌ █▌ █▌ █▌
1147-
█▌▐█ █▌ █▌▐█ █▌ ████ ███▌ █▌
1148-
█▌ ██▌ █▌ █▌ █▌ █▌ █▌
1149-
█▌ █▌ █▌ █▌ █▌ █▌ █▌
1150-
████▌ █▌ ▐▌ █████▌ ███▌ █
1102+
█ █▌ █████▌ ███▌ █████▌ █████▌ ████▌ ███▌ █████▌ ███▌ █▌
1103+
█▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌
1104+
█▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌
1105+
█▌▐█ █▌ ████ ███▌ █▌ ███ █▌ █▌ █▌ █▌ ████ █▌ █▌
1106+
█▌ ██▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌
1107+
█▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌
1108+
█▌ ▐▌ ████▌ ███ █▌ █████▌ ████▌ ████████▌██▌ █████
11511109
-->
11521110

1153-
<h2 id=nest-rule>
1154-
The ''@nest'' Rule</h2>
1111+
<h2 id=nested-declarations-rule>
1112+
The Nested Declarations Rule</h2>
11551113

11561114
For somewhat-technical reasons,
11571115
it's important to be able to distinguish properties
@@ -1205,34 +1163,21 @@ The ''@nest'' Rule</h2>
12051163
These run into the same problems as above.
12061164

12071165
To address all of these issue,
1208-
the <dfn at-rule>@nest</dfn> rule is defined:
1209-
1210-
<pre class=prod>
1211-
&lt;@nest> = @nest { <<block-contents>> }
1212-
</pre>
1166+
we instead wrap runs of consecutive directly-nested properties
1167+
in a <dfn export>nested declarations rule</dfn>.
12131168

12141169
Unless otherwise specified,
1215-
an ''@nest'' rule is a [=nested style rule=],
1170+
a [=nested declarations rule=] is a [=nested style rule=],
12161171
and acts identically to any other style rule.
12171172
It matches the exact same elements and pseudo-elements
12181173
as its parent style rule,
12191174
with the same specificity behavior.
12201175
<span class=note>(This is <em>similar to</em> being a style rule with an ''&'' selector,
12211176
but slightly more powerful,
12221177
as explained above.)</span>
1223-
If it does not have a parent style rule,
1224-
it matches elements as if it were a [=style rule=] with a '':scope'' selector.
1225-
1226-
Note: While it is <em>possible</em> to manually specify an ''@nest'' rule in a stylesheet,
1227-
there's never any reason to.
1228-
The parser automatically produces them when needed.
1229-
1230-
Issue: It's possible that we might make changes to further hide the existence of ''@nest'',
1231-
such as serializing as just its declarations when possible.
1232-
See <a href="https://github.com/w3c/csswg-drafts/issues/8738#issuecomment-2061777236">Issue 8738</a>.
12331178

12341179
<details class=note>
1235-
<summary>Why does the ''@nest'' rule exist?</summary>
1180+
<summary>Why does the [=nested declarations rule=] exist?</summary>
12361181

12371182
Originally, this specification grouped all declarations in style rules together,
12381183
"moving" them from their original location
@@ -1241,15 +1186,15 @@ The ''@nest'' Rule</h2>
12411186
in plain style rules,
12421187
using the ''&'' selector.
12431188

1244-
There are two major reasons we switched to instead use the ''@nest'' rule.
1189+
There are two major reasons we switched to instead use the [=nested declarations rule=].
12451190

12461191
First, using an ''& {...}'' rule to implicitly wrap declarations in a [=nested group rule=]
12471192
also changed the behavior.
12481193
As shown in the example following this note,
12491194
it breaks cases where the parent style rule contains pseudo-elements,
12501195
and even when that's not the case,
12511196
it potentially changes the specificity behavior of the nested declarations.
1252-
Switching to ''@nest'' avoids these problems,
1197+
Switching to the [=nested declarations rule=] avoids these problems,
12531198
making the behavior of nested ''@media''/etc
12541199
identical to the behavior of *non*-nested ''@media''/etc.
12551200

@@ -1262,7 +1207,7 @@ The ''@nest'' Rule</h2>
12621207
and in order to actually make that representable in the CSSOM,
12631208
that means they have to be wrapped in some kind of rule.
12641209
The same issues as the previous paragraph apply if we just use a normal ''& {...}'' rule,
1265-
so ''@nest'' lets us do so without side effects.
1210+
so the [=nested declarations rule=] lets us do so without side effects.
12661211
</details>
12671212

12681213
<div class=example>
@@ -1295,14 +1240,14 @@ The ''@nest'' Rule</h2>
12951240
}
12961241
```
12971242

1298-
Then the ''color: white'' is implicitly wrapped in an ''@nest'',
1243+
Then the ''color: white'' is implicitly wrapped in a [=nested declarations rule=],
12991244
which is guaranteed to match <em>exactly</em> the same as its parent style rule,
13001245
so the element <em>and</em> its pseudo-elements
13011246
would all have white text in a darkmode page.
13021247
</div>
13031248

13041249
<div class=example>
1305-
Declarations interleaved with rules get implicitly wrapped in an ''@nest'',
1250+
Declarations interleaved with rules get implicitly wrapped in a [=nested declarations rule=],
13061251
which makes them part of a separate style rule.
13071252
For example, given this CSS:
13081253

@@ -1320,7 +1265,7 @@ The ''@nest'' Rule</h2>
13201265
the ''color: black'' one.
13211266

13221267
The ''background: silver'' declaration
1323-
will instead be found in the implicitly-created ''@nest'' child rule,
1268+
will instead be found in the implicitly-created [=nested declarations rule|nested declarations child rule=],
13241269
at <code highlight=js>fooRule.cssRules[1].style</code>.
13251270
</div>
13261271

@@ -1354,20 +1299,20 @@ with the implied [=nesting selector=] inserted.
13541299
will serialize as ''& > .foo''.
13551300
</div>
13561301

1357-
The {{CSSNestRule}} Interface {#the-cssnestrule}
1302+
The {{CSSNestedDeclarations}} Interface {#the-cssnestrule}
13581303
-----------------------------
13591304

1360-
The {{CSSNestRule}} interface represents an ''@nest'' rule.
1305+
The {{CSSNestedDeclarations}} interface represents a [=nested declarations rule=].
13611306

13621307
<xmp class=idl>
13631308
[Exposed=Window]
1364-
interface CSSNestRule : CSSGroupingRule {
1309+
interface CSSNestedDeclarations : CSSRule {
13651310
[SameObject, PutForwards=cssText] readonly attribute CSSStyleProperties style;
13661311
};
13671312
</xmp>
13681313

13691314
<div algorithm>
1370-
The <dfn attribute for=CSSNestRule>style</dfn> attribute
1315+
The <dfn attribute for=CSSNestedDeclarations>style</dfn> attribute
13711316
must return a {{CSSStyleProperties}} object for the rule,
13721317
with the following properties:
13731318

@@ -1383,35 +1328,13 @@ interface CSSNestRule : CSSGroupingRule {
13831328
:: Null
13841329
</div>
13851330

1386-
<div class=example>
1387-
Note that interleaved declarations,
1388-
or all declarations in [=nested group rules=],
1389-
will be implicitly wrapped in ''@nest'' rules,
1390-
which will affect the serialization.
1391-
A [=nested group rule=] like:
1392-
1393-
<pre class=lang-css>
1394-
.foo {
1395-
@media (prefers-color-scheme: dark) {
1396-
color: white;
1397-
background: black;
1398-
}
1399-
}
1400-
</pre>
1331+
The {{CSSNestedDeclarations}} rule [=serialize a CSS rule|serializes=]
1332+
as if its [=CSS declaration block|declaration block=]
1333+
had been [=serialize a CSS declaration block|serialized=] directly.
14011334

1402-
will serialize as:
1403-
1404-
<pre class=lang-css>
1405-
.foo {
1406-
@media (prefers-color-scheme: dark) {
1407-
@nest {
1408-
color: white;
1409-
background: black;
1410-
}
1411-
}
1412-
}
1413-
</pre>
1414-
</div>
1335+
Note: This means that multiple adjacent [=nested declarations rules=]
1336+
(which is possible to create with e.g. {{CSSGroupingRule/insertRule}})
1337+
will collapse into a single rule when serialized and parsed again.
14151338

14161339

14171340
<!-- Big Text: changes -->
@@ -1439,6 +1362,9 @@ Significant changes since the
14391362
(<a href="https://github.com/w3c/csswg-drafts/issues/9069">Issue 9069</a>)
14401363

14411364
* Declarations intermixed with rules (or all declarations in nested group rules)
1442-
are now automatically wrapped in ''@nest'' rules.
1443-
(Also the ''@nest'' rule was added.)
1444-
(<a href="https://github.com/w3c/csswg-drafts/issues/8738">Issue 8738</a>)
1365+
are now automatically wrapped in <code>@nest</code> rules.
1366+
(Also the <code>@nest</code> rule was added.)
1367+
(<a href="https://github.com/w3c/csswg-drafts/issues/8738">Issue 8738</a>)
1368+
1369+
* Replaced <code>@nest</code> with [=nested declarations rules=].
1370+
(<a href="https://github.com/w3c/csswg-drafts/issues/10234">Issue 10234</a>)

css-syntax-3/Overview.bs

+3-3
Original file line numberDiff line numberDiff line change
@@ -2629,7 +2629,7 @@ Consume an at-rule</h4>
26292629
Note: If the result contains [=lists=] of [=declarations=],
26302630
how they're materialized in the CSSOM
26312631
depends on the rule.
2632-
Some turn them all into ''@nest'' rules,
2632+
Some turn them all into [=nested declarations rules=],
26332633
others will treat them all as declarations,
26342634
and others will treat the first item differently from the rest.
26352635

@@ -2758,7 +2758,7 @@ Consume a qualified rule</h4>
27582758
remove it from |child rules|
27592759
and assign it to |rule|'s declarations.
27602760
If any remaining items of |child rules| are [=lists=] of [=declarations=],
2761-
replace them with ''@nest'' [=at-rules=]
2761+
replace them with [=nested declarations rules=]
27622762
containing the [=list=] as its sole child.
27632763
Assign |child rules| to |rule|'s child [=rules=].
27642764

@@ -2802,7 +2802,7 @@ Consume a block's contents</h4>
28022802
a [=list=] of [=declarations=]
28032803
might be materialized in the CSSOM as either
28042804
a {{CSSStyleDeclaration}},
2805-
or as a {{CSSNestRule}}.
2805+
or as a {{CSSNestedDeclarations}} rule.
28062806

28072807
Let |rules| be an empty [=list=],
28082808
containing either [=rules=]

cssom-1/Overview.bs

+13-2
Original file line numberDiff line numberDiff line change
@@ -1845,13 +1845,24 @@ To <dfn export>serialize a CSS rule</dfn>, perform one of the following in accor
18451845

18461846
Issue: The "indented by two spaces" bit matches browsers, but needs work, see <a href="https://github.com/w3c/csswg-drafts/issues/5494">#5494</a>
18471847

1848-
To <dfn export>insert a CSS rule</dfn> <var>rule</var> in a CSS rule list <var>list</var> at index <var>index</var>, follow these steps:
1848+
To <dfn export>insert a CSS rule</dfn> <var>rule</var> in a CSS rule list <var>list</var> at index <var>index</var>,
1849+
with a flag <var>nested</var>,
1850+
follow these steps:
18491851
<ol>
18501852
<li>Set <var>length</var> to the number of items in <var>list</var>.
18511853
<li>If <var>index</var> is greater than <var>length</var>, then <a>throw</a>
18521854
an {{IndexSizeError}} exception.
18531855
<li>Set <var>new rule</var> to the results of performing <a>parse a CSS rule</a>
18541856
on argument <var>rule</var>.
1857+
<li>If <var>new rule</var> is a syntax error, and <var>nested</var> is set,
1858+
perform the following substeps:
1859+
<ul>
1860+
<li> Set <var>declarations</var> to the results of performing <a>parse a CSS declaration block</a>,
1861+
on argument <var>rule</var>.
1862+
<li> If <var>declarations</var> is a syntax error, <a>throw</a> a {{SyntaxError}} exception.
1863+
<li> Otherwise, set <var>new rule</var> to a new [=nested declarations rule=]
1864+
with <var>declarations</var> as it contents.
1865+
</ul>
18551866
<li>If <var>new rule</var> is a syntax error, <a>throw</a>
18561867
a {{SyntaxError}} exception.
18571868
<li>If <var>new rule</var> cannot be inserted into <var>list</var> at the zero-index position <var>index</var> due to constraints
@@ -2087,7 +2098,7 @@ The <dfn attribute for=CSSGroupingRule>cssRules</dfn> attribute must return a <c
20872098

20882099
The <dfn method for=CSSGroupingRule>insertRule(<var>rule</var>, <var>index</var>)</dfn> method must return the result of
20892100
invoking <a>insert a CSS rule</a> <var>rule</var> into the <a for=CSSRule>child CSS rules</a> at
2090-
<var>index</var>.
2101+
<var>index</var>, with the <var>nested</var> flag set.
20912102

20922103
The <dfn method for=CSSGroupingRule>deleteRule(<var>index</var>)</dfn> method must <a>remove a CSS rule</a> from the
20932104
<a for=CSSRule>child CSS rules</a> at <var>index</var>.

0 commit comments

Comments
 (0)