@@ -285,7 +285,7 @@ as well as other [=custom functions=] via <<dashed-function>>s.
285
285
286
286
The '@function/result' descriptor itself does not have a type,
287
287
but its [=resolve function styles|resolved=] value is type-checked
288
- during the [=substitute a dashed function|substitution=] of a <<dashed-function>> .
288
+ during the [=replace a dashed function|substitution=] of a <<dashed-function>> .
289
289
290
290
Arguments & Local Variables {#args}
291
291
-----------------------------------
@@ -385,7 +385,7 @@ with a <<dashed-function>>.
385
385
386
386
A <dfn><<dashed-function>></dfn> is a [=functional notation=]
387
387
whose function name starts with two dashes (U+002D HYPHEN-MINUS).
388
- Its syntax is:
388
+ Its [=argument grammar=] is:
389
389
390
390
<pre class="prod informative" nohighlight>
391
391
<dashed-function> = --*( <<declaration-value>> #? )
@@ -396,7 +396,7 @@ A <<dashed-function>> can only be used where ''var()'' is allowed.
396
396
If a property contains one or more <<dashed-function>> s,
397
397
the entire property’s grammar must be assumed to be valid at parse time.
398
398
At computed-value time,
399
- every <<dashed-function>> must be [=substitute a dashed function|substituted =]
399
+ every <<dashed-function>> must be [=replace a dashed function|replaced =]
400
400
before finally being checked against the property's grammar.
401
401
402
402
Note: Within the body of a [=custom function=] ,
@@ -420,18 +420,18 @@ a [=calling context's=] <dfn for="calling context">root element</dfn>
420
420
is the real element at the root of the [=calling context=] stack.
421
421
422
422
<div algorithm>
423
- To <dfn>substitute a dashed function</dfn> in a value ,
424
- with |dashed function| being a <<dashed-function>> :
423
+ To <dfn>replace a dashed function</dfn> |dashed function| ,
424
+ with a list of |arguments| :
425
425
426
426
1. Let |function| be the result of dereferencing
427
427
the |dashed function|'s name as a [=tree-scoped reference=] .
428
- If no such name exists, return failure .
429
- 2. [=substitute arbitrary substitution functions|Substitute=]
430
- any [= arbitrary substitution functions=]
431
- within |dashed function|'s arguments,
432
- then parse it as ''<<declaration-value>>#''
433
- and let | arguments| be the result
434
- (a comma-separated list of CSS values ).
428
+ If no such name exists, return the [=guaranteed-invalid value=] .
429
+ 2. For each |arg| in |arguments|,
430
+ [=substitute arbitrary subsitution functions=] in |arg|,
431
+ and replace |arg| with the result.
432
+
433
+ Note: This may leave some (or all) arguments as the [=guaranteed-invalid value=] ,
434
+ triggering [=default values=] (if any ).
435
435
3. If |dashed function| is being substituted into a property on an element,
436
436
let |calling context| be a [=calling context=]
437
437
with that element and that property
@@ -442,17 +442,12 @@ is the real element at the root of the [=calling context=] stack.
442
442
Let |calling context| be a [=calling context=]
443
443
with that "hypothetical element" and that descriptor.
444
444
445
- 5 . [=Evaluate a custom function=] ,
445
+ 4 . [=Evaluate a custom function=] ,
446
446
using |function|, |arguments|, and |calling context|,
447
- and replace the <<dashed-function>> with the [=equivalent token sequence=]
447
+ and return the [=equivalent token sequence=]
448
448
of the value resulting from the evaluation.
449
449
</div>
450
450
451
- If [=substitute a dashed function=] fails,
452
- and the substitution is taking place on a property's value,
453
- then the declaration containing the <<dashed-function>> becomes
454
- [=invalid at computed-value time=] .
455
-
456
451
<div class='example'>
457
452
A [=comma-containing productions|comma-containing value=]
458
453
may be passed as a single argument
@@ -468,6 +463,66 @@ then the declaration containing the <<dashed-function>> becomes
468
463
</pre>
469
464
</div>
470
465
466
+ <div class='example'>
467
+ In the following,
468
+ <code> --foo()</code> is in a cycle with itself:
469
+
470
+ <pre class='lang-css'>
471
+ @function --foo(--x) {
472
+ result: --foo(10);
473
+ }
474
+ </pre>
475
+
476
+ Similarly,
477
+ <code> --bar()</code> is in a cycle with itself,
478
+ even though the local variable <code> --x</code> is never referenced
479
+ by '@function/result' :
480
+
481
+ <pre class='lang-css'>
482
+ @function --bar() {
483
+ --x: --bar();
484
+ result: 1;
485
+ }
486
+ </pre>
487
+
488
+ However, <code> --baz()</code> is not in a cycle with itself here,
489
+ since we never evaluate the <code> result</code> declaration within
490
+ the <code> @media</code> rule:
491
+
492
+ <pre class='lang-css'>
493
+ @function --baz(--x) {
494
+ @media (unknown-feature) {
495
+ result: --baz(42);
496
+ }
497
+ result: 1;
498
+ }
499
+
500
+ </pre>
501
+ </div>
502
+
503
+ <div class='example'>
504
+ The function <code> --baz()</code> is not in a cycle in the example below:
505
+ even though <code> var(--x)</code> and <code> var(--y)</code> appear in the function body,
506
+ they refer to a [=function parameter=] and [=local variable=] , respectively.
507
+ The [=custom properties=] <code> --x</code> and <code> --y</code>
508
+ both reference <code> --baz()</code> , but that's fine:
509
+ those [=custom properties=] are not referenced within <code> --baz()</code> .
510
+
511
+ <pre class='lang-css'>
512
+ @function --baz(--x) {
513
+ --y: 10px;
514
+ result: calc(var(--x) + var(--y));
515
+ }
516
+
517
+ div {
518
+ --x: --baz(1px);
519
+ --y: --baz(2px);
520
+ width: var(--x); /* 11px */
521
+ height: var(--y); /* 12px */
522
+ }
523
+ </pre>
524
+ </div>
525
+
471
526
Evaluating Custom Functions {#evaluating-custom-functions}
472
527
----------------------------------------------------------
473
528
@@ -486,52 +541,71 @@ with its [=function parameters=] overriding "inherited" custom properties of the
486
541
and a list of CSS values |arguments|,
487
542
returning a CSS value:
488
543
489
- 1. If the number of items in |arguments|
544
+ 1. Let |substitution context| be a [=substitution context=]
545
+ containing &bs<<;"function", |custom function|&bs>> ;.
546
+
547
+ Note: Due to [=tree-scoped names|tree-scoping=] ,
548
+ the same function name may appear multiple times on the stack
549
+ while referring to different [=custom functions=] .
550
+ For this reason, the [=custom function=] itself is included
551
+ in the [=substitution context=] , not just its name.
552
+ 2. [=guarded|Guard=] |substitution context| for the remainder of this algorithm.
553
+ If |substitution context| is marked as [=cyclic substitution context|cyclic=] ,
554
+ return the [=guaranteed-invalid value=] .
555
+ 3. If the number of items in |arguments|
490
556
is greater than the number of [=function parameters=] in |custom function|,
491
557
return the [=guaranteed-invalid value=] .
492
- 2 . Let |registrations| be an initially empty set of [=custom property registrations=] .
493
- 3 . For each [=function parameter=] of |custom function|,
558
+ 4 . Let |registrations| be an initially empty set of [=custom property registrations=] .
559
+ 5 . For each [=function parameter=] of |custom function|,
494
560
create a [=custom property registration=]
495
561
with the parameter's name,
496
562
a syntax of the [=parameter type=] ,
497
563
an inherit flag of "true",
498
564
and no initial value.
499
565
Add the registration to |registrations|.
500
- 4 . If |custom function| has a [=custom function/return type=] ,
566
+ 6 . If |custom function| has a [=custom function/return type=] ,
501
567
create a [=custom property registration=]
502
568
with the name "return"
503
569
(violating the usual rules for what a registration's name can be),
504
570
a syntax of the [=custom function/return type=] ,
505
571
an inherit flag of "false",
506
572
and no initial value.
507
573
Add the registration to |registrations|.
508
- 5 . Let |argument rule| be an initially empty [=style rule=] .
509
- 6 . For each [=function parameter=] of |custom function|:
574
+ 7 . Let |argument rule| be an initially empty [=style rule=] .
575
+ 8 . For each [=function parameter=] of |custom function|:
510
576
1. Let |arg value| be the value of the corresponding argument in |arguments|,
511
577
or the [=guaranteed-invalid value=] if there is no corresponding argument.
512
578
2. Let |default value| be the parameter's [=default value=] .
513
579
3. Add a [=custom property=] to |argument rule|
514
580
with a name of the parameter's name,
515
581
and a value of ''first-valid(|arg value|, |default value|)'' .
516
- 7 . [=Resolve function styles=] using |argument styles|, |registrations|, and |calling context|.
582
+ 9 . [=Resolve function styles=] using |custom function|, |argument styles|, |registrations|, and |calling context|.
517
583
Let |argument styles| be the result.
518
- 8 . Let |body rule| be the [=function body=] of |custom function|,
584
+ 10 . Let |body rule| be the [=function body=] of |custom function|,
519
585
as a [=style rule=] .
520
- 9 . For each [=custom property registration=] of |registrations|,
586
+ 11 . For each [=custom property registration=] of |registrations|,
521
587
set its initial value
522
588
to the corresponding value in |argument styles|,
523
589
set its syntax
524
590
to the [=universal syntax definition=] ,
525
591
and prepend a [=custom property=] to |body rule|
526
592
with the property name and value in |argument styles|.
527
- 10 . [=Resolve function styles=] using |body rule|, |registrations|, and |calling context|.
593
+ 12 . [=Resolve function styles=] using |custom function|, |body rule|, |registrations|, and |calling context|.
528
594
Let |body styles| be the result.
529
- 11. Return the value of the '@function/result' property in |body styles|.
595
+ 13. If |substitution context| is marked as a [=cyclic substitution context=] ,
596
+ return the [=guaranteed-invalid value=] .
597
+
598
+ Note: Nested [=arbitrary substitution functions=]
599
+ may have marked |substitution context| as [=cyclic substitution context|cyclic=]
600
+ at some point after step 2,
601
+ for example when resolving '@function/result' .
602
+ 14. Return the value of the '@function/result' property in |body styles|.
530
603
</div>
531
604
532
605
<div algorithm>
533
606
To <dfn>resolve function styles</dfn> ,
534
- given a style rule |rule|,
607
+ given a [=custom function=] |custom function|,
608
+ a style rule |rule|,
535
609
a set of [=custom property registrations=] |registrations|,
536
610
and a [=calling context=] |calling context|,
537
611
returning a set of [=computed value|computed=] styles:
@@ -565,6 +639,17 @@ with its [=function parameters=] overriding "inherited" custom properties of the
565
639
Note: ''result: inherit'' , for example,
566
640
will cause the <<dashed-function>> to <em> evaluate to</em> the ''inherit'' keyword,
567
641
similar to ''var(--unknown, inherit)'' .
642
+ * For a given [=custom property=] |prop|,
643
+ during [=property replacement=] for that property,
644
+ the [=substitution context=] also includes |custom function|.
645
+ In other words, the [=substitution context=] is
646
+ &bs<<;"property", |prop|'s name, |custom function|&bs>> ;
647
+
648
+ Note: Due to dynamic scoping,
649
+ the same property name may appear multiple times on the stack
650
+ while referring to different [=custom properties=] .
651
+ For this reason, the [=custom function=] itself is included
652
+ in the [=substitution context=] , not just its name.
568
653
569
654
3. Determine the [=computed value=] of all [=custom properties=]
570
655
and the '@function/result' "property" on |el|,
@@ -588,88 +673,6 @@ with its [=function parameters=] overriding "inherited" custom properties of the
588
673
will be used from these styles.
589
674
</div>
590
675
591
-
592
-
593
-
594
- Cycles {#cycles}
595
- ----------------
596
-
597
- The ''@function/result'' descriptor and [=local variables=]
598
- within a [=custom function=]
599
- may reference other [=custom functions=] or [=custom properties=] ,
600
- and may therefore create [[css-variables-1#cycles|cycles]] .
601
-
602
- For each element, add a node for every specified [=custom function=]
603
- to the graph described in [[css-variables-1#cycles]] ;
604
- add a node for each [=local variable=]
605
- defined within each of those functions;
606
- then, for each [=custom function=] <var> func</var> , add edges as follows:
607
-
608
- * From <var> func</var> to any [=custom function=]
609
- referenced by a <<dashed-function>> within <var> func</var> 's body.
610
- * From <var> func</var> to any [=custom property=] or [=local variable=]
611
- referenced by a ''var()'' within <var> func</var> 's body.
612
- * To <var> func</var> from any [=custom property=] or [=local variable=]
613
- that references <var> func</var>
614
- using a <<dashed-function>> .
615
-
616
- A <<dashed-function>> referencing a [=custom function=]
617
- which is part of a cycle
618
- makes the containing [=declaration=] [=invalid at computed-value time=] .
619
-
620
- Note: Cycles are disallowed even through branches that are not taken
621
- during execution.
622
-
623
- <div class='example'>
624
- In the following,
625
- <code> --foo()</code> is in a cycle with itself,
626
- even though the media query never evaluates to "true":
627
-
628
- <pre class='lang-css'>
629
- @function --foo(--x) {
630
- @media (unknown-feature) {
631
- result: --foo(42);
632
- }
633
- result: 1;
634
- }
635
- </pre>
636
-
637
- Similarly,
638
- <code> --bar()</code> is in a cycle with itself,
639
- even though the local variable <code> --x</code> is never referenced:
640
-
641
- <pre class='lang-css'>
642
- @function --bar() {
643
- --x: --bar();
644
- result: 1;
645
- }
646
- </pre>
647
- </div>
648
-
649
- <div class='example'>
650
- The function <code> --baz()</code> is not in a cycle in the example below:
651
- even though <code> var(--x)</code> and <code> var(--y)</code> appear in the function body,
652
- they refer to a [=function parameter=] and [=local variable=] , respectively.
653
- The [=custom properties=] <code> --x</code> and <code> --y</code>
654
- both reference <code> --baz()</code> , but that's fine:
655
- those [=custom properties=] are not referenced within <code> --baz()</code> .
656
-
657
- <pre class='lang-css'>
658
- @function --baz(--x) {
659
- --y: 10px;
660
- result: calc(var(--x) + var(--y));
661
- }
662
-
663
- div {
664
- --x: --baz(1px);
665
- --y: --baz(2px);
666
- width: var(--x); /* 11px */
667
- height: var(--y); /* 12px */
668
- }
669
- </pre>
670
- </div>
671
-
672
-
673
676
<!-- Big Text: execution
674
677
675
678
█████▌ █ █ █████▌ ███▌ █▌ █▌ █████▌ ████ ███▌ █ █▌
0 commit comments