@@ -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>
204204Specifying CSS Syntax in CSS: the <<syntax>> type</h3>
205205
206206Some 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=] ,
210209allow you to specify how <em> another</em> value is meant to be parsed.
211210This is declared via the <<syntax>> production,
212211which resembles a limited form of the CSS [=value definition syntax=]
213212used in specifications to define CSS features,
214213and 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
229230A <<syntax-component>> consists of either
@@ -276,11 +277,73 @@ is a convenience form equivalent to <code><transform-function>+</code>.
276277
277278[=Whitespace=] is not allowed
278279between the angle bracket <<delim-token>> s (<code> <</code> <code> ></code> )
279- and the <<syntax-type>> they enclose,
280+ and the <<syntax-type-name >> they enclose,
280281nor is [=whitespace=] allowed to precede a <<syntax-multiplier>> .
281282
282283Note: The [=whitespace=] restrictions also apply to <code> <transform-list></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 <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">
286349Extensions 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><attr-name></dfn> = [ <<ident-token>> '|' ]? <<ident-token>>
1337-
1338- <dfn><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><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- < stock>
1500- < wood length="12"/>
1501- < wood length="5"/>
1502- < metal length="19"/>
1503- < wood length="4"/>
1504- < /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 <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