-
Notifications
You must be signed in to change notification settings - Fork 22
/
index.bs
348 lines (283 loc) · 11.4 KB
/
index.bs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
<pre class='metadata'>
Title: CSS Extend Rule
Abstract: This module defines the ''@extend'' rule, which allows elements to act as if they matched other selectors.
This makes it easier to "subclass" styling in a page,
when some new type of element should act like an existing element,
but with tweaks.
Editor: Tab Atkins, Google, http://xanthir.com
ED: https://tabatkins.github.io/specs/css-extend-rule/
Status: DREAM
Shortname: extend-rule
Level: 1
Ignored Terms: getelementsbytagname()
</pre>
<pre class='link-defaults'>
spec: selectors-4; type: selector; text: :active
</pre>
Introduction {#intro}
=====================
Sometimes, when designing a page,
an author might create some styles for a given type of element,
such as "error" messages.
Later, they might realize they need to create a "subclass" of the first type,
such as a "serious error" message,
which is styled the same way as "error",
but with a few tweaks to make it more distinctive.
Currently, CSS does not have a good way to handle this.
If the author has control over the HTML,
they can declare that every element with a class of "serious-error"
must also have a class of "error".
This, however, is error-prone--
it's easy to forget to add the "error" class to an element,
causing confusing styling issues,
and any scripting that creates or manipulates error elements
has to know to maintain the states properly
(for example, any time they remove the "error" class,
they have to remember to check for and remove "serious-error" as well).
Alternately, this can be handled in the CSS--
every time a style rule contains a ''.error'' selector,
the selector can be duplicated with ''.serious-error'' replacing it.
This, too, is error-prone:
it's easy for typos or inattention to cause the duplicated selectors to drift apart,
and it's easy, when adding new ''.error'' rules,
to forget to duplicate the selector.
The ''@extend'' rule, defined in this specification,
fixes this common issue.
It allows an author to declare that certain elements,
such as everything matching ''.serious-error'',
must <em>act as if</em> they had the necessary features to match another selector,
such as ''.error''.
<div class='example'>
For example, the following code declares that ''.serious-error'' elements should act as if they were ''.error'' elements as well:
<pre class='lang-css'>
.error {
color: red;
border: thick dotted red;
}
.serious-error {
@extend .error;
font-weight: bold;
}
</pre>
Now an element like <code><div class=serious-error></code> will have red text and border,
just like elements with <code>class=error</code>,
but will also use bold text.
</div>
This allows authors to write simple HTML,
applying either <code>class=error</code> or <code>class=serious-error</code> to elements as appropriate,
and write simple CSS,
creating style rules that just mention ''.error'' or ''.serious-error'',
secure in the knowledge that the former rules will also apply to serious errors.
The ''@extend'' Rule {#extend-rule}
===================================
The <dfn>@extend</dfn> rule declares
that a matched element must act as if it had the necessary qualities to match another specified selector.
Its syntax is:
<pre class='prod'>@extend <<compound-selector>>;</pre>
The ''@extend'' rule is only allowed inside of style rules.
In any other context, an ''@extend'' rule is invalid.
An ''@extend'' rule modifies the way that selector matching works
for the elements matched by the style rule the ''@extend'' selector is inside of,
known as the <dfn>extended elements</dfn> for that rule.
The argument to ''@extend'' is the <dfn>extension selector</dfn>.
The rule's <a>extended elements</a> must,
for the purpose of determining if selectors match them,
act as if they had the necessary <a>features</a>/state/etc to match the <a>extension selector</a>,
in addition to their pre-existing <a>features</a>/state/etc.
<div class='example'>
For example, in the following code:
<pre class='lang-css'>
.serious-error {
@extend .error;
}
</pre>
All elements matching the ''.serious-error'' selector
must act as if they also had an "error" class
for the purpose of matching selectors,
regardless of what their actual set of classes is.
</div>
Issue: Should this only affect selectors in CSS,
or should it affect all APIs using selectors?
Dunno which is saner for browsers;
probably all selector-based APIs.
Do other query APIs, like {{getElementsByTagName()}},
rely on the same machinery?
If so, should we generalize this to allow host languages to declare arbitrary querying APIs to be "selector-ish"?
The ''@extend'' rule only affects the <a>extended elements</a>
as long as the rule it's inside of matches them.
<div class='example'>
For example, if the rule containing ''@extend'' is in an ''@media'' block:
<pre class='lang-css'>
.error {
color: red;
}
@media (width > 600px) {
.serious-error {
@extend .error;
font-weight: bold;
}
.error {
width: 100%;
}
}
</pre>
Then the ''.serious-error'' elements only act as if they have an <code>error</code> class
when the page's width is greater than ''600px''.
</div>
<div class='example'>
Note that the <a>extension selector</a> can specify more than classes.
For example, in the following code:
<pre class='lang-css'>
.my-button {
@extend button;
}
</pre>
Any elements with <code>class=my-button</code> receive the same styling as actual <a element>button</a> elements,
as if they had a tagname of <css>button</css> in addition to their normal tagname.
Similarly, in the following code:
<pre class='lang-css'>
.perma-pressed-button {
@extend .button:active;
}
</pre>
Any ''.perma-pressed'' elements are styled as if they were '':active'',
so that any styling applied to "pressed" buttons via '':active'' rules applies to them as well.
</div>
<div class='example'>
The ''@extend'' rule effectively adds qualities to an element,
so that it matches other rules.
The selector used to apply the ''@extend'' rule has no effect on this.
For example, in the following code:
<pre class='lang-css'>
.red-text { color: red; }
.blue-text { color: blue; }
#sidebar { @extend .red-text; }
div { @extend .blue-text; }
</pre>
A naive author looking at the code and wondering how a <code><div id=sidebar></code> element would be styled
might assume that it gets red text,
as an ID selector is used to ''@extend'' the ''.red-text'' class,
versus a much less specific tagname selector.
However, this is wrong--
the element gets blue text,
as the ''.red-text'' and ''.blue-text'' rules have equal specificity,
and the ''.blue-text'' rule appears later in the stylesheet.
The specificity of the rules that caused the element to match ''.red-text'' or ''.blue-text'' are irrelevant here.
While this may in some cases be confusing,
it can also be a great benefit in some cases.
For example,
an author can define a lot of styles with simple, one-class (or one <a>placeholder selector</a>) rules,
effectively ignoring specificity entirely,
then apply them via longer, much more specific selectors,
using ''@extend'' to invoke the behavior of the simpler rules.
This can allow an author to avoid many of the specificity problems of using IDs in rules, for example.
</div>
''@extend'' Chaining {#extend-chaining}
---------------------------------------
Multiple ''@extend'' rules can be "chained",
with one rule adding certain qualities to an element,
which cause another style rule containing an ''@extend'' to match.
Note: This falls out of the definition automatically.
It is called out separately for clarity,
not because it's a separate feature that needs to be specifically defined.
<div class='example'>
For example,
the following code using ''@extend'':
<pre class='lang-css'>
.error {
color: red;
}
.serious-error {
@extend .error;
font-weight: bold;
}
.super-serious-error {
@extend .serious-error;
animation: flashing 1s infinite;
}
</pre>
is equivalent to the following code without ''@extend'':
<pre class='lang-css'>
.error, .serious-error, .super-serious-error {
color: red;
}
.serious-error, .super-serious-error {
font-weight: bold;
}
.super-serious-error {
animation: flashing 1s infinite;
}
</pre>
</div>
The Placeholder Selector ''%foo'' {#placeholder}
================================================
The ''@extend'' rule originates in CSS preprocessors, such as SASS.
Experience with those tools shows that it's often useful to define generic, "functional" sets of styles
that don't apply to any elements directly,
then use ''@extend'' to give that behavior to <em>semantic</em> classnames
which are more meaningful within their project.
<div class='example'>
For example, the "media block" is a common functional sort of styling,
originating from OOCSS,
that describes a box with a picture on one side and text on the other.
It might be used like the following:
<pre class='lang-css'>
.media-block {
overflow: auto;
}
.media-block > img {
float: left;
}
...
.image-post {
@extend .media-block;
... /* additional styles to tweak the display */
}
</pre>
</div>
However, this also carries the possibility of confusion.
In the above example, ''.media-block'' is just used to give a name to the pattern,
so that other rules can ''@extend'' it.
It's not meant to be used in a document--
there shouldn't be any elements with <code>class=media-block</code>--
but this isn't obvious from the code.
It's easy for later maintainers of the file to accidentally use ''.media-block'' directly on an element,
and modify it for their own uses
(after all, if they search the codebase, they'll find no elements on the page using it!),
perhaps accidentally breaking elements using it in ''@extend''.
To avoid situations like this,
and make it more clear that one is developing a "generic"/"functional"/"structural" set of styles,
the <dfn>placeholder selector</dfn> can be used.
Its syntax is similar to a <a>class selector</a>,
but is prefixed by a ''%'' (U+0025 PERCENT SIGN)
rather than a period.
<div class='example'>
The previous example could be more clearly written using a <a>placeholder selector</a>:
<pre class='lang-css'>
%media-block {
overflow: auto;
}
%media-block > img {
float: left;
}
...
.image-post {
@extend %media-block;
}
</pre>
</div>
Host languages must not provide any way for an element to match a <a>placeholder selector</a>;
the only way for an element to match one is by using an ''@extend'' rule.
This ensures that no element will ever directly match the styles using one,
even by accident,
and it can't be accidentally reused for an element directly.
<a>Placeholder selectors</a> have the same specificity as <a>class selectors</a>.
Issue: Or should they have slightly less, so concrete classes can reliably override?
This would mean putting a fourth number into the specificity 3-tuple.
Acknowledgements {#acks}
========================
The editor would like to thank the following people:
* <a href="https://twitter.com/stubbornella">Nicole Sullivan</a> for <a href="http://www.stubbornella.org/content/2009/11/09/css-wish-list/">first coming up with the idea for @extend</a>.
* <a href="https://twitter.com/chriseppstein">Chris Eppstein</a> and <a href="https://twitter.com/nex3">Natalie Weizenbaum</a>
for <a href="http://chriseppstein.github.io/blog/2009/10/12/css-class-inheritance/">developing and programming</a> the modern incarnation of ''@extend'' in Sass.
* The Sass community, for using ''@extend'' so extensively that its lack in CSS couldn't be ignored.