Skip to content

Commit 95e6ec6

Browse files
committed
[css-values-5] Replace attr()'s syntax argument with <syntax>, and fix up its parsing/substitution rules as a result. #10437
1 parent 73b34bd commit 95e6ec6

File tree

1 file changed

+136
-148
lines changed

1 file changed

+136
-148
lines changed

css-values-5/Overview.bs

Lines changed: 136 additions & 148 deletions
Original file line numberDiff line numberDiff line change
@@ -172,8 +172,8 @@ Commas in Function Arguments</h4>
172172
Note: Because {} wrappers are allowed even when not explicitly required,
173173
they can be used defensively around values
174174
when the author isn't sure if they'll end up containing commas or not,
175-
due to [=arbitrary-substitution functions=] like ''var()''.
176-
For example, ''font-family: random-item(--x, {var(--list1)}, monospace)''
175+
due to [=arbitrary substitution functions=] like ''var()''.
176+
For example, <l property>''font-family: random-item(--x, {var(--list1)}, monospace)''</l>
177177
will work correctly
178178
regardless of whether the ''--list1'' custom property
179179
contains a comma-separated list or not.
@@ -204,17 +204,16 @@ Commas in Function Arguments</h4>
204204
Specifying CSS Syntax in CSS: the <<syntax>> type</h3>
205205

206206
Some features in CSS,
207-
such as the ''attr()'' function,
208-
[=registered custom properties=],
209-
or [=custom function parameters=],
207+
such as the ''attr()'' function
208+
or [=registered custom properties=],
210209
allow you to specify how <em>another</em> value is meant to be parsed.
211210
This is declared via the <<syntax>> production,
212211
which resembles a limited form of the CSS [=value definition syntax=]
213212
used in specifications to define CSS features,
214213
and which represents a [=syntax definition=]:
215214

216215
<pre class="prod def" nohighlight>
217-
<dfn><<syntax>></dfn> = '*' | <<syntax-component>> [ <<syntax-combinator>> <<syntax-component>> ]+
216+
<dfn><<syntax>></dfn> = '*' | <<syntax-component>> [ <<syntax-combinator>> <<syntax-component>> ]+ | <<syntax-string>>
218217
<dfn><<syntax-component>></dfn> = <<syntax-single-component>> <<syntax-multiplier>>?
219218
| '<' transform-list '>'
220219
<dfn><<syntax-single-component>></dfn> = '<' <<syntax-type-name>> '>' | <<ident>>
@@ -224,6 +223,8 @@ and which represents a [=syntax definition=]:
224223
| url | transform-function
225224
<dfn><<syntax-combinator>></dfn> = '|'
226225
<dfn><<syntax-multiplier>></dfn> = [ '#' | '+' ]
226+
227+
<dfn><<syntax-string>></dfn> = <<string>>
227228
</pre>
228229

229230
A <<syntax-component>> consists of either
@@ -276,11 +277,73 @@ is a convenience form equivalent to <code>&lt;transform-function&gt;+</code>.
276277

277278
[=Whitespace=] is not allowed
278279
between the angle bracket <<delim-token>>s (<code>&lt;</code> <code>&gt;</code>)
279-
and the <<syntax-type>> they enclose,
280+
and the <<syntax-type-name>> they enclose,
280281
nor is [=whitespace=] allowed to precede a <<syntax-multiplier>>.
281282

282283
Note: The [=whitespace=] restrictions also apply to <code>&lt;transform-list&gt;</code>.
283284

285+
A <<syntax-string>> is a <<string>>
286+
whose value successfully [=CSS/parses=] as a <<syntax>>,
287+
and represents the same value as that <<syntax>> would.
288+
289+
Note: <<syntax-string>> mostly exists for historical purposes;
290+
before <<syntax>> was defined,
291+
the ''@property'' rule used a <<string>> for this purpose.
292+
293+
<h4 id=parse-syntax>
294+
Parsing as <<syntax>></h4>
295+
296+
The purpose of a <<syntax>>
297+
is usually to specify how to parse another value
298+
(such as the value of a [=registered custom property=],
299+
or an attribute value in ''attr()'').
300+
However, the generic [=CSS/parse something according to a CSS grammar=] algorithm
301+
returns an unspecified internal structure,
302+
since parse results might be ambiguous
303+
and need further massaging.
304+
305+
To avoid these issues and get a well-defined result,
306+
use [=parse with a &lt;syntax>=]:
307+
308+
<div algorithm>
309+
To <dfn export>parse with a <<syntax>></dfn>
310+
given a [=string=] or [=list=] or [=CSS/component values=] |values|,
311+
a <<syntax>> value |syntax|,
312+
and optionally an element |el| for context,
313+
perform the following steps.
314+
It returns either CSS values,
315+
or the [=guaranteed-invalid value=].
316+
317+
1. [=Parse a list of component values=] from |values|,
318+
and let |raw parse| be the result.
319+
320+
2. If |el| was given,
321+
[=substitute arbitrary substitution functions=] in |raw parse|,
322+
and set |raw parse| to that result.
323+
324+
3. [=CSS/parse=] |values| according to |syntax|,
325+
with a ''*'' value treated as <code><<declaration-value>>?</code>,
326+
and let |parsed result| be the result.
327+
If |syntax| used a ''|'' combinator,
328+
let |parsed result| be the parse result from the first matching clause.
329+
330+
4. If |parsed result| is failure,
331+
return the [=guaranteed-invalid value=].
332+
333+
5. Assert: |parsed result| is now a well-defined list of one or more CSS values,
334+
since each branch of a <<syntax>> defines an unambiguous parse result
335+
(or the ''*'' syntax is unambiguous on its own).
336+
337+
6. Return |parsed result|.
338+
</div>
339+
340+
Note: This algorithm does not resolved the parsed values
341+
into [=computed values=];
342+
the context in which the value is used will usually do that already,
343+
but if not,
344+
the invoking algorithm will need to handle that on its own.
345+
346+
284347

285348
<h2 id="level-4-extensions">
286349
Extensions to Level 4 Value Types</h3>
@@ -637,7 +700,7 @@ Interpolation Progress Functional Notations</h2>
637700
following a common syntactic pattern:
638701

639702
<pre class=prod>
640-
<var>progress-function</var>() = <var>progress-function</var>( <var>progress value</var> from <var>start value</var> to <var>end value</var> )
703+
<var ignore>progress-function</var>() = <var ignore>progress-function</var>( <var ignore>progress value</var> from <var ignore>start value</var> to <var ignore>end value</var> )
641704
</pre>
642705

643706
Each resolves to a <<number>>
@@ -1331,24 +1394,15 @@ Ian's proposal:
13311394
substitutes a [=custom property=] value into a function.
13321395

13331396
<pre class=prod>
1334-
attr() = attr( <<attr-name>> <<attr-type>>? , <<declaration-value>>?)
1397+
attr() = attr( <<attr-name>> <<syntax>>? , <<declaration-value>>?)
13351398
13361399
<dfn>&lt;attr-name></dfn> = [ <<ident-token>> '|' ]? <<ident-token>>
1337-
1338-
<dfn>&lt;attr-type></dfn> = string | ident | color | number | percentage |
1339-
length | angle | time | frequency | flex | <<dimension-unit>>
13401400
</pre>
13411401

13421402
<!-- Switch the <attr-name> to just use <q-name>
13431403
when Namespaces is rewritten
13441404
to use the current grammar structures. -->
13451405

1346-
The <dfn>&lt;dimension-unit></dfn> production matches a literal "%" character
1347-
(that is, a <<delim-token>> with a value of "%")
1348-
or an ident whose value is any of the CSS units
1349-
for <<length>>, <<angle>>, <<time>>, <<frequency>>, or <<flex>> values
1350-
(such as ''px'' or ''ms'').
1351-
13521406
The arguments of ''attr()'' are:
13531407

13541408
: <<attr-name>>
@@ -1370,16 +1424,24 @@ Ian's proposal:
13701424
if applied to a pseudo-element,
13711425
the attribute is looked up on the pseudo-element's [=originating element=].
13721426

1373-
: <<attr-type>>
1427+
: <<syntax>>
13741428
::
1375-
Specifies what kind of CSS value
1376-
the attribute's value will be interpreted into
1377-
(the ''attr()''’s <dfn dfn for=attr()>substitution value</dfn>)
1378-
and what, if any, special parsing will be done to the value.
1379-
1380-
The possible values and their behavior are defined in [[#attr-types]].
1381-
1382-
Defaults to ''string'' if omitted.
1429+
Specifies how the attribute value is [=CSS/parsed=] into a CSS value.
1430+
Values that fail to parse according to the syntax
1431+
trigger fallback.
1432+
1433+
Omitting the <<syntax>> argument
1434+
causes the attribute's literal value
1435+
to be treated as the value of a CSS string,
1436+
with no CSS parsing performed at all
1437+
(including CSS escapes, whitespace removal, comments, etc).
1438+
1439+
Note: This is different from specifying a syntax of ''*'',
1440+
which still triggers CSS parsing
1441+
(but with no requirements placed on it
1442+
beyond that it parse validly),
1443+
and which substitutes the result of that parsing directly,
1444+
rather than as a <<string>> value.
13831445

13841446
: <<declaration-value>>
13851447
::
@@ -1388,9 +1450,9 @@ Ian's proposal:
13881450
if the attribute is missing
13891451
or fails to parse as the specified type.
13901452

1391-
If the <<attr-type>> argument is ''string'',
1392-
defaults to the empty string if omitted;
1393-
otherwise, defaults to the [=guaranteed-invalid value=] if omitted.
1453+
If the <<syntax>> argument is omitted,
1454+
the fallback defaults to the empty string if omitted;
1455+
otherwise, it defaults to the [=guaranteed-invalid value=] if omitted.
13941456

13951457
If a property contains one or more ''attr()'' functions,
13961458
and those functions are syntactically valid,
@@ -1400,116 +1462,30 @@ Ian's proposal:
14001462

14011463
<div class='note'>
14021464
Note that the default value need not be of the type given.
1403-
For instance, if the type required of the attribute by the author is ''px'',
1465+
For instance, if the type required of the attribute by the author is ''<number px>'',
14041466
the default could still be <css>auto</css>,
1405-
like in ''width: attr(size px, auto);''.
1467+
like in ''width: attr(size <number px>, auto);''.
14061468
</div>
14071469

1408-
<h4 id="attr-types">
1409-
''attr()'' Types</h4>
1410-
1411-
The behavior of the ''attr()'' function
1412-
depends partially on the value of the <<attr-type>> argument:
1413-
1414-
<dl dfn-type=value dfn-for=attr()>
1415-
: <dfn>string</dfn>
1416-
:: The [=substitution value=] is a CSS string,
1417-
whose value is the literal value of the attribute.
1418-
(No CSS parsing or "cleanup" of the value is performed.)
1419-
1420-
No value triggers fallback.
1421-
1422-
: <dfn>ident</dfn>
1423-
:: The [=substitution value=] is a CSS <<custom-ident>>,
1424-
whose value is the literal value of the attribute,
1425-
with [=strip leading and trailing ASCII whitespace|leading and trailing ASCII whitespace stripped=].
1426-
(No CSS parsing of the value is performed.)
1427-
1428-
If the attribute value,
1429-
after trimming,
1430-
is the empty string,
1431-
there is instead no [=substitution value=].
1432-
1433-
If the <<custom-ident>>’s value is a [=CSS-wide keyword=]
1434-
or <css>default</css>,
1435-
there is instead no [=substitution value=].
1436-
1437-
: <dfn>color</dfn>
1438-
::
1439-
[=Parse a component value=] from the attribute's value.
1440-
If the result is a <<hex-color>>
1441-
or a [=named color=] ident,
1442-
the [=substitution value=] is that result as a <<color>>.
1443-
1444-
Otherwise there is no [=substitution value=].
1445-
1446-
: <dfn>number</dfn>
1447-
::
1448-
[=Parse a component value=] from the attribute's value.
1449-
If the result is a <<number-token>>,
1450-
the result is the [=substitution value=].
1451-
1452-
Otherwise, there is no [=substitution value=].
1453-
1454-
: <dfn>percentage</dfn>
1455-
::
1456-
[=Parse a component value=] from the attribute's value.
1457-
If the result is a <<percentage-token>>,
1458-
the result is the [=substitution value=].
1459-
1460-
Otherwise, there is no [=substitution value=].
1461-
1462-
: <dfn>length</dfn>
1463-
: <dfn>angle</dfn>
1464-
: <dfn>time</dfn>
1465-
: <dfn>frequency</dfn>
1466-
: <dfn>flex</dfn>
1467-
::
1468-
[=Parse a component value=] from the attribute's value.
1469-
If the result is a <<dimension-token>>
1470-
whose unit matches the given type,
1471-
the result is the [=substitution value=].
1472-
1473-
Otherwise, there is no [=substitution value=].
1474-
1475-
: <dfn><<dimension-unit>></dfn>
1476-
::
1477-
[=Parse a component value=] from the attribute's value.
1478-
If the result is a <<number-token>>,
1479-
the [=substitution value=] is a dimension
1480-
with the result's value,
1481-
and the given unit.
1482-
1483-
Otherwise, there is no [=substitution value=].
1484-
</dl>
1485-
1486-
Issue: Do we want to allow [=math functions=] as attr values
1487-
for all the numeric types?
1488-
And color functions for "color"?
1489-
I think we do,
1490-
but I'd have to check the contents to make sure they don't contain further reference functions;
1491-
<code highlight=html>foo="rgb(var(--red), 0, 0)"</code>
1492-
needs to be illegal for ''attr(foo color)''.
1493-
14941470
<div class="example">
14951471
This example shows the use of attr() to visually illustrate data
14961472
in an XML file:
14971473

1498-
<pre>
1499-
&lt;stock>
1500-
&lt;wood length="12"/>
1501-
&lt;wood length="5"/>
1502-
&lt;metal length="19"/>
1503-
&lt;wood length="4"/>
1504-
&lt;/stock>
1474+
<xmp>
1475+
<stock>
1476+
<wood length="12"/>
1477+
<wood length="5"/>
1478+
<metal length="19"/>
1479+
<wood length="4"/>
1480+
</stock>
15051481

15061482
stock::before {
15071483
display: block;
15081484
content: "To scale, the lengths of materials in stock are:";
15091485
}
15101486
stock > * {
15111487
display: block;
1512-
width: attr(length em, 0px);
1488+
width: attr(length <number em>, 0px);
15131489
height: 1em;
15141490
border: solid thin;
15151491
margin: 0.5em;
@@ -1520,33 +1496,45 @@ Ian's proposal:
15201496
metal {
15211497
background: silver url(metal.png);
15221498
}
1523-
</pre>
1499+
</xmp>
15241500
</div>
15251501

15261502
<h4 id=attr-substitution>
15271503
''attr()'' Substitution</h4>
15281504

1529-
Issue: attr() and var() substitute at the same time,
1530-
so I should probably rewrite [=substitute a var()=]
1531-
to be more generally about "substitute a reference"
1532-
and just use that for both of these functions.
1533-
1534-
''attr()'' functions are [=substitute an attr()|substituted=] at computed-value time.
1535-
If a declaration,
1536-
once all ''attr()'' functions are substituted in,
1537-
does not match its declared grammar,
1538-
the declaration is [=invalid at computed-value time=].
1539-
1540-
To <dfn export>substitute an ''attr()''</dfn>:
1541-
1542-
1. If the ''attr()'' function has a [=substitution value=],
1543-
replace the ''attr()'' function by the [=substitution value=].
1544-
2. Otherwise, if the ''attr()'' function has a fallback value as its last argument,
1545-
replace the ''attr()'' function by the fallback value.
1546-
If there are any ''var()'' or ''attr()'' references in the fallback,
1547-
[=substitute an attr()|substitute=] them as well.
1548-
3. Otherwise, the property containing the ''attr()'' function
1549-
is [=invalid at computed-value time=].
1505+
''attr()'' is an [=arbitrary substitution function=],
1506+
similar to ''var()'',
1507+
and so is replaced with the value it represents (if possible)
1508+
at [=computed value=] time;
1509+
otherwise, it's replaced with the [=guaranteed-invalid value=],
1510+
which will make its declaration [=invalid at computed-value time=].
1511+
1512+
<div algorithm>
1513+
To <dfn export>[=resolve an arbitrary substitution function|resolve an attr() function=]</dfn>:
1514+
1515+
1. Let |el| be the element that the style containing the ''attr()'' function
1516+
is being applied to.
1517+
Let |attr name| be the attribute name specified in the function.
1518+
Let |syntax| be the <<syntax>> specified in the function,
1519+
or null if it was omitted.
1520+
Let |fallback| be the <<declaration-value>>? argument specified in the function,
1521+
or the [=guaranteed-invalid value=] if it was omitted.
1522+
1523+
2. If there is no attribute named |attr name| on |el|,
1524+
return the [=guaranteed-invalid value=] and |fallback|.
1525+
Otherwise, let |attr value| be that attribute's value.
1526+
1527+
3. If |syntax| is null,
1528+
return a CSS <<string>>
1529+
whose value is |attr value|.
1530+
1531+
Note: No parsing or modification of any kind is performed on the value.
1532+
1533+
4. [=Parse with a &lt;syntax>=] |attr value|, with |syntax| and |el|.
1534+
Return the result and |fallback|.
1535+
</div>
1536+
1537+
15501538

15511539

15521540
<h4 id=attr-security>

0 commit comments

Comments
 (0)