forked from w3c/csswg-drafts
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathOverview.bs
355 lines (293 loc) · 12.5 KB
/
Overview.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
349
350
351
352
353
354
355
<pre class="metadata">
Title: CSS Conditional Rules Module Level 5
Group: csswg
Shortname: css-conditional
Level: 5
Status: FPWD
Prepare for TR: yes
Date: 2021-12-21
!Delta Spec: yes
Work Status: Exploring
ED: https://drafts.csswg.org/css-conditional-5/
TR: https://www.w3.org/TR/css-conditional-5/
Editor: L. David Baron, Mozilla https://www.mozilla.org/, https://dbaron.org/, w3cid 15393
Editor: Elika J. Etemad / fantasai, Invited Expert, http://fantasai.inkedblade.net/contact, w3cid 35400
Editor: Chris Lilley, W3C, https://svgees.us/, w3cid 1438
Abstract: This module contains the features of CSS
for conditional processing of parts of style sheets,
based on capabilities of the processor or the environment
the style sheet is being applied in.
It includes and extends the functionality of CSS Conditional 4 [[!css-conditional-4]],
adding the generalized conditional rule ''@when''
and the chained conditional rule ''@else'',
as well as introducing font processing queries
to the [=supports query=] syntax used in ''@supports'' rules.
Default Highlight: css
</pre>
<pre class="link-defaults">
spec: css-conditional-3
type: dfn; text: conditional group rule
</pre>
<h2 id="introduction">
Introduction</h2>
ISSUE: This is currently an early draft of the things that are <em>new</em> in level 5.
The features in Level 3 and Level 4 are still defined
in [[css-conditional-3]] and [[css-conditional-4]]
and have not yet been copied here.
CSS Conditional Level 5 extends
the ''@supports'' rule and [=supports query=] syntax
to allow testing for supported font technologies.
It also adds an ''@when'' rule,
which generalizes the concept of a conditional rule.
Anything that can be expressed in an existing conditional rule
can be expressed in ''@when''
by wrappng it in an appropriate function
to declare what kind of condition it is.
This allow authors to easily combine multiple types of queries,
such as media queries and supports queries,
in a single boolean expression.
Without this,
authors must rely on nesting separate conditional rules,
which is harder to read and write,
presupposes the conditions are to be conjoined with the “and” boolean relation
(with no easy way to indicate anything else),
and restricts their utility in the proposed [=conditional rule chains=].
It also adds ''@else'' rules,
which immediately follow other conditional rules
and automatically qualify their conditions
as the inverse of the immediately preceding rule’s conditions,
such that only the first matching rule in a [=conditional rule chain=]
is applied.
<h2 id="at-supports-ext">
Extensions to the ''@supports'' rule</h2>
This level of the specification extends the <<supports-feature>> syntax as follows:
<pre class="prod def" nohighlight>
<dfn><supports-feature></dfn> = <<supports-selector-fn>> | <<supports-font-tech-fn>>
| <<supports-font-format-fn>> | <<supports-decl>>
<dfn><supports-font-tech-fn></dfn> = font-tech( <<font-tech>> )
<dfn><font-tech></dfn> = [ features-opentype | features-aat | features-graphite
| color-colrv0 | color-colrv1 | color-svg | color-sbix | color-cbdt
| variations | palettes | incremental ]
<dfn><supports-font-format-fn></dfn> = font-format( <<font-format>> )
<dfn><font-format</dfn> = [ collection | embedded-opentype | opentype
| svg | truetype | woff | woff2 ]
</pre>
ISSUE: <<font-format>> and <<font-tech>> should be imported from css-fonts-4, not defined here.
: <<supports-font-tech-fn>>
::
The result is true if the UA
<a href="#dfn-support-font-tech">supports the font tech</a>
provided as an argument to the function.
Note: The allowed values for the ''font-tech()'' function
are the same as those for the ''tech()'' function
in the '@font-face' '@font-face/src' descriptor.
: <<supports-font-format-fn>>
::
The result is true if the UA
<a href="#dfn-support-font-format">supports the font format</a>
provided as an argument to the function.
Note: The allowed values for the ''font-format()'' function
are the same as those for the ''format()'' function
in the '@font-face' '@font-face/src' descriptor.
<h3 id="support-definition-ext">
Extensions to the definition of support</h3>
A CSS processor is considered to
<dfn export for=CSS id="dfn-support-font-tech">support a font tech</dfn>
when it is capable of utilising the specified [[css-fonts-4#font-tech-definitions]]
in layout and rendering.
A CSS processor is considered to
<dfn export for=CSS id="dfn-support-font-format">support a font format</dfn>
when it is capable of utilising the specified [[css-fonts-4#font-format-definitions]]
in layout and rendering.
<h2 id="when-rule">
Generalized Conditional Rules: the ''@when'' rule</h2>
The <dfn>@when</dfn> at-rule is a [=conditional group rule=]
that generalizes the individual [=conditional group rules=]
such as ''@media'' and ''@supports''.
It is defined as:
<pre class=prod>
@when <<boolean-condition>> {
<<stylesheet>>
}
</pre>
Where <<boolean-condition>> is a boolean algebra a la [[mediaqueries-4#mq-syntax]],
but with ''media()'' and ''supports()'' functions as leaves.
Issue: Define "boolean algebra, with X as leaves" in a generic way in Conditional,
so all the conditional rules can reference it directly,
rather than having to redefine boolean algebra on their own.
The ''media()'' and ''supports()'' functions are defined as:
<pre class=prod>
<dfn>media()</dfn> = media( [ <<mf-plain>> | <<mf-boolean>> | <<mf-range>> ] )
<dfn>supports()</dfn> = supports( <<declaration>> )
</pre>
A ''media()'' or ''supports()'' function is associated the boolean result
that its contained condition is associated with.
<h2 id="else-rule">
Chained Conditionals: the ''@else'' rule</h2>
Usually, [=conditional group rules=] are independent;
each one has a separate condition
evaluated without direct reference to any other rule,
and decides whether or not to apply its contained rules
based solely on its condition.
This is fine for simple conditions,
but makes it difficult to write a collection of conditionals
that are meant to be mutually exclusive:
authors have to very carefully craft their conditions
to not activate when the other rules are meant to,
and make sure the collection of conditionals
don't accidentally <em>all</em> exclude some situation
which is then left unstyled.
The <dfn>@else</dfn> rule is a [=conditional group rule=]
used to form [=conditional rule chains=],
which associate multiple [=conditional rules=]
and guarantee that only the first one that matches
will evaluate its condition as true.
It is defined as:
<pre class=prod>
@else <<boolean-condition>>? {
<<stylesheet>>
}
</pre>
''@else'' is interpreted identically to ''@when''.
If its <<boolean-condition>> is omitted,
it's treated as having a condition that's always true.
A <dfn export>conditional rule chain</dfn> is
a series of consecutive [=conditional group rules=],
starting with a [=conditional group rule=] other than ''@else'',
followed by zero or more ''@else'' rules.
There cannot be anything between the successive [=conditional group rules=]
other than whitespace and/or comments;
any other token “breaks” the chain.
Issue: Should we require that only the last ''@else'' in a chain can have an omitted condition?
It's not uncommon for me, when debugging code,
to short-circuit an if-else chain by setting one of them to "true";
I presume that would be similarly useful in CSS?
It's still pretty easy to see you've done something wrong if you omit the condition accidentally.
Within a [=conditional rule chain=],
the conditions of each [=conditional group rule=] are evaluated in order.
If one of them is true,
the conditions of all <em>following</em> [=conditional group rules=] in the chain
evaluate to false,
regardless of their stated condition.
An ''@else'' rule that is not part of a [=conditional rule chain=]
is invalid and must be ignored.
<div class=example>
For example, here's a (somewhat silly) conditional chain:
<pre class="lang-css">
@when media(width >= 400px) and media(pointer: fine) and supports(display: flex) {
/* A */
} @else supports(caret-color: pink) and supports(background: double-rainbow()) {
/* B */
} @else {
/* C */
}
</pre>
Exactly one of the preceding rules will be chosen,
even though the second rule
doesn't exclude large widths, fine points, or flexbox support,
and the last rule
doesn't specify anything at all.
To achieve the same result without [=conditional rule chains=],
you'd need to write:
<pre class="lang-css">
@media (width >= 400px) and (pointer: fine) {
@supports (display: flex) {
/* A */
}
@supports not (display: flex) {
@supports (caret-color: pink) and (background: double-rainbow()) {
/* B */
}
@supports not ((caret-color: pink) and (background: double-rainbow())) {
/* C */
}
}
}
@media not ((width >= 400px) and (pointer: fine)) {
@supports (caret-color: pink) and (background: double-rainbow()) {
/* B */
}
@supports not ((caret-color: pink) and (background: double-rainbow())) {
/* C */
}
}
</pre>
This is simultaneously hard to read,
requires significant duplication of both conditions and contents,
and is <em>very</em> difficult to write correctly.
<!-- (I wrote it wrong <em>twice</em> while producing this example.) -->
If the conditions got any more complicated
(which is not unusual in real-world content),
the example would get <em>significantly</em> worse.
</div>
<div class="example">
In this example, three different color font technologies
are tested, in order of preference,
plus a monochrome fallback.
The most capable, COLRv1, supports both gradients and font variations;
the next best choice, SVG, supports gradients
while the least capable, COLRv0, supports flat color fill only.
The fallback has no test condition,
so will always be chosen unless one of the earlier conditions succeeds.
<pre class="lang-css">
@when font-tech(color-COLRv1) and font-tech(variations) {
@font-face { font-family: icons; src: url(icons-gradient-var.woff2); }
}
@else font-tech(color-SVG) {
@font-face { font-family: icons; src: url(icons-gradient.woff2); }
}
@else font-tech(color-COLRv0) {
@font-face { font-family: icons; src: url(icons-flat.woff2); }
}
@else {
@font-face { font-family: icons; src: url(icons-fallback.woff2); }
}
</pre>
Notice that in this example,
the variable color font is only downloaded
if COLRv1 is supported
and font variations are also supported.
Notice too that only one of the available options will be downloaded;
this would not be the case without ''@when'' and ''@else'',
as the next example shows.
</div>
<div class="example">
In this example,
although it appears that the fallback will not be used
if COLRv1 is supported,
in fact both fonts will be downloaded,
which wastes bandwidth if it is not used.
The fallback might still be used for some characters;
for example, if the color font supports only Latin,
while the fallback supports Latin and Greek.
<pre class="lang-css">
@font-face { font-family: icons; src: url(icons-fallback.woff2);
@supports font-tech(color-COLRv1) {
@font-face { font-family: icons; src: url(icons-gradient-var.woff2); }
}
</pre>
</div>
<h2 class=no-num id="security">Security Considerations</h2>
No security issues have been raised against this document
<h2 class=no-num id="privacy">Privacy Considerations</h2>
<!-- COPY FROM L3 when importing the rest of the spec -->
The ''font-tech()'' and ''font-format()'' functions
may provide information about the user's software
such as its version
and whether it is running with non-default settings that enable or disable certain features.
This information can also be determined through other APIs.
However, the features in this specification are one of the ways this information
is exposed on the Web.
This information can also, in aggregate, be used to improve the accuracy of
<a href="https://www.w3.org/2001/tag/doc/unsanctioned-tracking/">fingerprinting</a> of the user.
<h2 class=no-num id="acknowledgments">Acknowledgments</h2>
The ''@when'' and ''@else'' rules are based on a proposal by Tab Atkins.
<h2 id='changes' class='no-num'>
Changes</h2>
<h3 id="changes-from-L4" class="no-num">
Additions since Level 4</h3>
<ul>
<li>Added ''@when'' and ''@else''.
<li>Extended [=supports queries=] to express font capabilities
via ''font-tech()'' and ''font-format()''.
</ul>