Skip to content

Commit 8e3f5f7

Browse files
committed
[css-extensions] First commit of CSS Extensions, per WG resolution.
1 parent 3269e31 commit 8e3f5f7

2 files changed

Lines changed: 908 additions & 0 deletions

File tree

css-extensions/Overview.bs

Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
<h1>CSS Extensions</h1>
2+
<pre class='metadata'>
3+
Group: CSSWG
4+
Shortname: css-extensions
5+
Level: 1
6+
Status: ED
7+
ED: http://dev.w3.org/csswg/css-extensions
8+
Editor: Tab Atkins, Google, http://xanthir.com/contact/
9+
Abstract: This specification defines methods for authors to extend and enhance various CSS features.
10+
</pre>
11+
12+
<h2 id='intro'>
13+
Introduction</h2>
14+
15+
When authoring CSS,
16+
one often encounters significant repetition in certain features.
17+
For example, a given media query might be repeated in several places,
18+
or a selector meant to apply to all heading elements
19+
requires specifying '':matches(h1, h2, h3, h4, h5, h6)'' in every location that uses it.
20+
21+
This repetition makes stylesheets more verbose and difficult to read,
22+
and also affects maintenance,
23+
as the author has to keep each repetition in sync when making any changes.
24+
25+
This specification defines methods for extending several CSS features
26+
so that a long or repeatedly-used value can be given a short, memorable name instead,
27+
or a feature can be given a more complex definition controlled by a scripting language.
28+
This makes stylesheets easier to read,
29+
and more powerful in general,
30+
as authors can extend the feature-set of CSS themselves
31+
rather than waiting for standards bodies to define new features for them.
32+
33+
<h2 id='extension-name'>
34+
Extension Names</h2>
35+
36+
All extensions defined in this specification use a common syntax for defining their ”names”:
37+
the <<extension-name>> production.
38+
An <dfn>&lt;extension-name></dfn> is any <a>identifier</a> that starts with two dashes (U+002D HYPHEN-MINUS),
39+
like ''--foo'', or even exotic names like ''--'' or ''------''.
40+
The CSS language will never use identifiers of this form for any language-defined purpose,
41+
so it's safe to use them for author-defined purposes
42+
without ever having to worry about colliding with CSS-defined names.
43+
44+
<h2 id='custom-selectors'>
45+
Custom Selectors</h2>
46+
47+
A <dfn>custom selector</dfn> is defined with the ''@custom-selector'' rule:
48+
49+
<pre class='prod'><dfn>@custom-selector</dfn> = @custom-selector <<extension-name>> <<selector>> ;</pre>
50+
51+
This defines a <a>custom selector</a> which is written as a <a spec=selectors>pseudo-class</a> with the given <<extension-name>>,
52+
and represents a '':matches()'' selector using the provided <<selector>> as its argument.
53+
54+
<div class='example'>
55+
For example, if an author wanted to easily refer to all heading elements in their HTML document,
56+
they could create an alias:
57+
58+
<pre>
59+
@custom-selector :--heading h1, h2, h3, h4, h5, h6;
60+
61+
:--heading { /* styles for all headings */ }
62+
:--heading + p { /* more styles */ }
63+
/* etc */
64+
</pre>
65+
</div>
66+
67+
<h3 id='script-custom-selectors'>
68+
Script-based Custom Selectors</h3>
69+
70+
<div class='issue'>
71+
This one's more complicated than MQs.
72+
Brian Kardell came up with a good proposal for evaluating selectors as JS functions that return a boolean,
73+
which had decent performance characteristics by specifying the qualities of the element it was based on
74+
(which determined when it would be called).
75+
76+
<pre>
77+
&lt;script>
78+
CSS.customSelector.set("_foo",
79+
{"predicate": function(el){...},
80+
"matches": "a"});
81+
&lt;/script>
82+
</pre>
83+
84+
"matches" is an optional selector specifying what subset of elements the custom selector is valid for.
85+
The selector is automatically false for elements that don't match,
86+
and the predicate isn't called.
87+
88+
By default, the predicate is called whenever there's a mutation in an element that matches the "matches" selector,
89+
or one of its descendants.
90+
91+
You should be able to suppress the auto-calling,
92+
and be able to trigger the predicate to run manually.
93+
That way you can use mutation listeners manually to only call the predicate when necessary.
94+
95+
We should probably offer some sugar for filtering the list of mutations that trigger the predicate to be called.
96+
Maybe just a list of attributes that you'll be caring about? And/or tagnames?
97+
98+
Maybe let the pseudo-class also accept an argument,
99+
and pass it (as a serialized string) as a second argument to the predicate.
100+
'':_foo'' would pass <code>null</code>,
101+
while '':_foo()'' would pass <code>""</code>.
102+
</div>
103+
104+
<h3 id='custom-selectors-cssom'>
105+
CSSOM</h3>
106+
107+
<p class='issue'>
108+
Fill in.
109+
110+
<h2 id='custom-functions'>
111+
Custom Functions</h2>
112+
113+
<div class='issue'>
114+
Interesting possibilities here.
115+
Definitely need some way to define custom functions in CSS.
116+
This would, for example, let people define whatever color function they want,
117+
such as implementing the <a href="http://www.boronine.com/husl/">HUSL</a> color space.
118+
119+
Definitely need a JS interface.
120+
What options are needed?
121+
122+
Call time/frequency:
123+
124+
<ul>
125+
<li>
126+
Default should probably treat the function as a preprocessor,
127+
calling the JS function once per instance in the stylesheet
128+
and substituting in the returned value.
129+
130+
<li>
131+
Should probably have an option to allow calling per element/instance combo, too.
132+
Gets called more as match results change.
133+
</ul>
134+
135+
We can take some cues from my thoughts on a random() function.
136+
It needs per-instance,
137+
per-element&amp;instance,
138+
and per "identifier", so you can reuse the same value in multiple spots.
139+
That last one can probably be handled manually by the JS,
140+
so we don't have to privilege a particular argument as an identifier.
141+
142+
We'd need to provide the context in which it's used.
143+
Which property, for example.
144+
Should we allow them to be used in other places,
145+
or should we just define more contextual locations as we go?
146+
That is, should we allow custom-defined functions in @supports with this API,
147+
or should we add a <code>.customSupports</code> map?
148+
I suspect that individual cases will have their own useful contextual information,
149+
so it's better to specialize each instance of custom functions.
150+
151+
How much can we do in pure CSS?
152+
Being able to substitute values depending on MQs or support queries would be useful.
153+
To get *real* use out of it, though, I suspect we'd need fuller support for conditionals,
154+
likely in the form of SASS's ''@if'' or something similar.
155+
</div>
156+
157+
<h2 id='custom-combinators'>
158+
Custom Selector Combinators</h2>
159+
160+
<div class='issue'>
161+
Selectors are made of two pieces:
162+
simple selectors,
163+
and combinators.
164+
We should allow custom combinators too.
165+
166+
This is JS-only, because it's transforming elements, not filtering them,
167+
and you can't express any useful transformations in pure CSS.
168+
169+
You provide a function which,
170+
when given an element,
171+
produces a list of zero or more elements.
172+
173+
For examples, with ''div /--foo/ span'',
174+
the CSS engine will match the first part of the selector
175+
and find all the div elements.
176+
It passes that list to the function registered for the --foo combinator,
177+
and expects to get a new list of elements returned.
178+
It then continues on its way,
179+
filtering that list to include only span elements, etc.
180+
181+
A child combinator would be something like:
182+
183+
<pre>
184+
CSS.customCombinator.set("--child", function(el) {
185+
return el.children;
186+
});
187+
</pre>
188+
189+
Then ''div /--child/ span'' would be identical to ''div > span''.
190+
191+
If we generalize a selector with a custom combinator to ''A /--custom/ B'',
192+
then the UA would automatically call the --custom function
193+
whenever new elements match ''A''.
194+
If elements stop matching ''A'',
195+
it won't bother;
196+
it'll just drop them from the result.
197+
198+
Alternately, the function could take a list of elements
199+
(all the elements matching ''A'')
200+
and return a new list of elements.
201+
This would be a bit more complicated for the author,
202+
but would allow more variety in the types of combinators that could be defined,
203+
as you could define things that depend on the entire set of matched elements.
204+
For example, you could define ''A /nth 1/ B''
205+
to give only the first element from the set of ''A'' matches.
206+
207+
(Maybe we allow both variants,
208+
since the per-element one is easier to optimize and program against,
209+
but the per-set one allows some useful stuff.)
210+
211+
Similarly to custom pseudo-classes,
212+
we'd allow arguments,
213+
with them parsed eagerly per-instance
214+
and passed to the combinator function.
215+
216+
If we do the per-element combinator function,
217+
we could potentially cache the results,
218+
so that it never needs to be called again for the same element.
219+
Possibly have a flag that turns off this behavior,
220+
so that you're guaranteed to be called again.
221+
</div>
222+
223+
<h2 id='custom-atrules'>
224+
Custom At-Rules</h2>
225+
226+
<div class='issue'>
227+
This one's even less developed,
228+
but it would be interesting to allow custom at-rules as well.
229+
It's definitely pure-JS as well.
230+
231+
Unsure exactly what's best here.
232+
Possibly register a callback per rule,
233+
which is called with the prelude/contents of the at-rule?
234+
235+
Should we do the callback approach,
236+
or just maintain a list of custom at-rules
237+
and let scripts parse them themselves?
238+
Unfortunately, the latter means we'd have to have a special mechanism to alert scripts
239+
when new at-rules get added or removed.
240+
241+
For a lot of these at-rules, we may want a way to know when they're "applied"--
242+
when, according to the built-in at-rules like @media and @supports,
243+
the rule would be applied.
244+
</div>

0 commit comments

Comments
 (0)