Skip to content

Commit 9af12cf

Browse files
andruudAnders Hartvoll Ruudtabatkins
authored
[css-variables] Handle short-circuiting var(), argument grammars, etc (#12164)
* [css-variables] Handle short-circuiting var(), argument grammars, etc The main part of the cycle behavior is now specified in css-values, so css-variables does not really need that much on that topic anymore. This should mostly bring css-variables-1/2 up to date with #11500. * Update css-variables-1/Overview.bs --------- Co-authored-by: Anders Hartvoll Ruud <andruud@google.com> Co-authored-by: Tab Atkins Jr. <jackalmage@gmail.com>
1 parent 1b466cd commit 9af12cf

File tree

2 files changed

+143
-272
lines changed

2 files changed

+143
-272
lines changed

css-variables-1/Overview.bs

Lines changed: 71 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -509,132 +509,6 @@ Guaranteed-Invalid Values</h3>
509509
the only way to create the [=guaranteed-invalid value=]
510510
is by having an invalid [=arbitrary substitution function=].
511511

512-
513-
514-
<!-- Big Text: cycles
515-
516-
███▌ █ ▐▌ ███▌ █▌ █████▌ ███▌
517-
█▌ █▌ ▐▌ █ █▌ █▌ █▌ █▌ █▌ █▌
518-
█▌ █ ▐▌ █▌ █▌ █▌ █▌
519-
█▌ ▐▌█ █▌ █▌ ████ ███▌
520-
█▌ █▌ █▌ █▌ █▌ █▌
521-
█▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌ █▌
522-
███▌ █▌ ███▌ █████ █████▌ ███▌
523-
-->
524-
525-
<h3 id='cycles'>
526-
Resolving Dependency Cycles</h3>
527-
528-
<a>Custom properties</a> are left almost entirely unevaluated,
529-
except that they allow and evaluate the ''var()'' function in their value.
530-
This can create cyclic dependencies
531-
where a custom property uses a ''var()'' referring to itself,
532-
or two or more <a>custom properties</a> each attempt to refer to each other.
533-
534-
For each element,
535-
create a directed dependency graph,
536-
containing nodes for each <a>custom property</a>.
537-
If the value of a <a>custom property</a> <var>prop</var>
538-
contains a ''var()'' function referring to the property <var>var</var>
539-
(including in the fallback argument of ''var()''),
540-
add an edge between <var>prop</var> and the <var>var</var>.
541-
<span class='note'>Edges are possible from a custom property to itself.</span>
542-
543-
If there is a cycle in the dependency graph,
544-
all the <a>custom properties</a> in the cycle
545-
are [=invalid at computed-value time=].
546-
547-
<wpt>
548-
variable-cycles.html
549-
variable-declaration-30.html
550-
variable-declaration-48.html
551-
variable-declaration-49.html
552-
variable-declaration-50.html
553-
variable-reference-39.html
554-
</wpt>
555-
556-
Note: Defined properties that participate in a dependency cycle
557-
either end up with invalid variables in their value
558-
(becoming [=invalid at computed-value time=]),
559-
or define their own cyclic handling
560-
(like 'font-size' using ''em'' values).
561-
They do not compute to the [=guaranteed-invalid value=]
562-
like custom properties do.
563-
564-
<div class='example'>
565-
This example shows a custom property safely using a variable:
566-
567-
<pre>
568-
:root {
569-
--main-color: #c06;
570-
--accent-background: linear-gradient(to top, var(--main-color), white);
571-
}
572-
</pre>
573-
574-
The '--accent-background' property
575-
(along with any other properties that use ''var(--main-color)'')
576-
will automatically update when the '--main-color' property is changed.
577-
</div>
578-
579-
<div class='example invalid-example'>
580-
On the other hand,
581-
this example shows an invalid instance of variables depending on each other:
582-
583-
<pre>
584-
:root {
585-
--one: calc(var(--two) + 20px);
586-
--two: calc(var(--one) - 20px);
587-
}
588-
</pre>
589-
590-
Both '--one' and '--two' are now [=invalid at computed-value time=],
591-
and compute to the [=guaranteed-invalid value=]
592-
rather than lengths.
593-
</div>
594-
595-
It is important to note that
596-
<a>custom properties</a> resolve any ''var()'' functions in their values at computed-value time,
597-
which occurs <em>before</em> the value is inherited.
598-
In general,
599-
cyclic dependencies occur only when multiple custom properties on the same element refer to each other;
600-
custom properties defined on elements higher in the element tree can never cause a cyclic reference with properties defined on elements lower in the element tree.
601-
602-
<wpt>
603-
variable-declaration-51.html
604-
variable-declaration-52.html
605-
</wpt>
606-
607-
<div class='example'>
608-
For example,
609-
given the following structure,
610-
these custom properties are <strong>not</strong> cyclic,
611-
and all define valid variables:
612-
613-
<xmp highlight=markup>
614-
<one><two><three /></two></one>
615-
<style>
616-
one { --foo: 10px; }
617-
two { --bar: calc(var(--foo) + 10px); }
618-
three { --foo: calc(var(--bar) + 10px); }
619-
</style>
620-
</xmp>
621-
622-
The &lt;one> element defines a value for '--foo'.
623-
The &lt;two> element inherits this value,
624-
and additionally assigns a value to '--bar' using the ''foo'' variable.
625-
Finally,
626-
the &lt;three> element inherits the '--bar' value
627-
<em>after</em> variable substitution
628-
(in other words, it sees the value ''calc(10px + 10px)''),
629-
and then redefines '--foo' in terms of that value.
630-
Since the value it inherited for '--bar' no longer contains a reference to the '--foo' property defined on &lt;one>,
631-
defining '--foo' using the ''var(--bar)'' variable is not cyclic,
632-
and actually defines a value that will eventually
633-
(when referenced as a variable in a normal property)
634-
resolve to ''30px''.
635-
</div>
636-
637-
638512
<!-- Big Text: var()
639513

640514
█▌ █▌ ███▌ ████▌ ██ ██
@@ -658,7 +532,12 @@ Using Cascading Variables: the ''var()'' notation</h2>
658532
<dfn>var()</dfn> = var( <<custom-property-name>> , <<declaration-value>>? )
659533
</pre>
660534

661-
The ''var()'' function is an [=arbitrary substitution function=].
535+
The ''var()'' function is an [=arbitrary substitution function=],
536+
and its [=argument grammar=] is:
537+
538+
<pre class='prod'>
539+
<dfn><<var-args>></dfn> = var( <<declaration-value>> , <<declaration-value>>? )
540+
</pre>
662541

663542
<wpt>
664543
variable-reference-07.html
@@ -824,27 +703,81 @@ Using Cascading Variables: the ''var()'' notation</h2>
824703
</pre>
825704
</div>
826705

827-
<div algorithm="resolve a var()">
828-
To <dfn export>[=resolve an arbitrary substitution function|resolve a var() function=]</dfn>:
706+
<div algorithm="replace a var()">
707+
To <dfn export>[=replace an arbitrary substitution function|replace a var() function=]</dfn>,
708+
given a list of |arguments|:
709+
710+
1. Let |el| be the element that the style containing the ''var()'' function
711+
is being applied to.
712+
Let |first arg| be the first <<declaration-value>> in |arguments|.
713+
Let |second arg| be the <<declaration-value>>? passed after the comma,
714+
or null if there was no comma.
829715

830-
1. Let |result| be the value of the [=custom property=]
831-
named by the function's first argument,
832-
on the element the function's property is being applied to.
716+
2. [=Substitute arbitrary substitution functions=] in |first arg|,
717+
then [=CSS/parse=] it as a <<custom-property-name>>.
718+
If parsing returned a <<custom-property-name>>,
719+
let |result| be the [=computed value=]
720+
of the corresponding [=custom property=] on |el|.
721+
Otherwise,
722+
let |result| be the [=guaranteed-invalid value=].
833723

834-
2. Let |fallback| be the value of the function's second argument,
835-
defaulting to the [=guaranteed-invalid value=]
836-
if it doesn't have a second argument.
724+
Note: Determining the [=computed value=] for the [=custom property=]
725+
implies that [=property replacement=] takes place,
726+
which may cause a [=cyclic substitution context|cycle=].
837727

838728
3. If the [=custom property=]
839729
named by the ''var()''’s first argument
840730
is [=animation-tainted=],
841731
and the ''var()'' is being used in a property that is [=not animatable=],
842732
set |result| to the [=guaranteed-invalid value=].
843733

844-
4. Return |result| and |fallback|.
734+
3. If |result| contains the [=guaranteed-invalid value=],
735+
and |second arg| was provided,
736+
set |result| to the result of [=substitute arbitrary substitution functions=]
737+
on |second arg|.
738+
739+
4. Return |result|.
740+
</div>
741+
742+
<div class='example'>
743+
Due to [=property replacement=],
744+
[=custom properties=] can form [=cyclic substitution context|cycles=]:
745+
746+
<pre>
747+
:root {
748+
--one: calc(var(--two) + 20px);
749+
--two: calc(var(--one) - 20px);
750+
}
751+
</pre>
752+
In the above,
753+
both '--one' and '--two' compute to the [=guaranteed-invalid value=],
754+
since their [=substitution contexts=] have been marked
755+
as [=cyclic substitution contexts|cyclic=].
845756
</div>
846757

758+
<wpt>
759+
variable-cycles.html
760+
variable-declaration-30.html
761+
variable-declaration-48.html
762+
variable-declaration-49.html
763+
variable-declaration-50.html
764+
variable-reference-39.html
765+
</wpt>
766+
767+
<div class='example'>
768+
Note that the [=custom property=] name looked up by a ''var()''
769+
may itself come from a ''var()'' function:
847770

771+
<pre>
772+
:root {
773+
--other: 10px;
774+
--myvar: --other;
775+
--result: var(var(--myvar));
776+
}
777+
</pre>
778+
Since the inner ''var()'' is resolved before the outer ''var()'',
779+
the computed value of '--result' becomes 10px.
780+
</div>
848781

849782
<!-- Big Text: cssom
850783

@@ -986,6 +919,8 @@ Changes Since the 16 June 2022 CR Snapshot</h3>
986919

987920
* Clarified that the comment-insertion can happen with 0+ comments between the original tokens, not just exactly 1.
988921
* Clarified the transition behavior of custom properties, in a note
922+
* Made ''var()'' short-circuiting.
923+
(<a href="https://github.com/w3c/csswg-drafts/issues/11500">Issue 11500</a>)
989924

990925
<h3 id='changes-20211111'>
991926
Changes Since the 11 November 2021 CR Draft</h3>

0 commit comments

Comments
 (0)