Skip to content

Commit 127301a

Browse files
committed
[css-mixins-1] Talk about element-dependent env variables
1 parent f999785 commit 127301a

File tree

1 file changed

+128
-0
lines changed

1 file changed

+128
-0
lines changed

css-mixins-1/Overview.bs

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1055,6 +1055,97 @@ aren't visible to anything outside of the [=mixin body=].
10551055
and the ''.warning'' rule would not be able to use them.
10561056
</div>
10571057

1058+
Note as well that [=scoped environment variables=] do not have an element context,
1059+
so they can't fully resolve values that require an element context,
1060+
like ''em'' lengths or ''var()'' functions,
1061+
at definition time.
1062+
Instead, they'll be resolved at each point they're used,
1063+
similar to an unregistered [=custom property=].
1064+
1065+
<div class=example>
1066+
For example, this mixin applies a size to an element, its parent, and its children.
1067+
If an ''em'' length is used, all of these might be different values:
1068+
1069+
<xmp highlight=css>
1070+
@mixin --triple-border(--size <length>) {
1071+
&, :has(&), & > * {
1072+
border-width: env(--size);
1073+
}
1074+
}
1075+
section {
1076+
font-size: 16px;
1077+
}
1078+
section > h1 {
1079+
font-size: 30px;
1080+
@apply --triple-border(.5em);
1081+
}
1082+
section > h1 > small {
1083+
font-size: 20px;
1084+
}
1085+
</xmp>
1086+
1087+
In this example,
1088+
despite them all being set with the same ''env(--size)'' value,
1089+
the `section` element has a border of ''8px'',
1090+
the `h1` element has a border of ''15px'',
1091+
and the `small` element has a border of ''10px''.
1092+
1093+
There are some ways to work around this, if desired.
1094+
For example, the value can be stored in a [=registered custom property=]
1095+
with the appropriate type,
1096+
so it resolves on one element and then inherits as the absolute value,
1097+
or passed through a [=custom function=] with a typed argument.
1098+
1099+
<xmp highlight=css>
1100+
@function --as-length(--arg <length>) { result: var(--arg); }
1101+
@mixin --triple-border(--size <length>) {
1102+
:has(&) {
1103+
--triple-border-size: --as-length(env(--size));
1104+
}
1105+
&, :has(&), & > * {
1106+
border-width: var(--triple-border-size);
1107+
}
1108+
}
1109+
section {
1110+
font-size: 16px;
1111+
}
1112+
section > h1 {
1113+
font-size: 30px;
1114+
@apply --triple-border(.5em);
1115+
}
1116+
section > h1 > small {
1117+
font-size: 20px;
1118+
}
1119+
</xmp>
1120+
1121+
In the above code, the [=mixin parameter=]
1122+
is set to a [=custom property=] on the parent element,
1123+
where it's forced to resolve as a length
1124+
due to being passed through the [=custom function=].
1125+
All the styles then use that [=custom property=]
1126+
(via ''var()'')
1127+
rather than the [=mixin parameter=]
1128+
(via ''env()''),
1129+
so they all share the same already-resolved value.
1130+
1131+
(Note that this value is resolved on the parent element
1132+
the [=custom property=] is defined on,
1133+
becoming ''8px'',
1134+
rather than resolving against the element the [=mixin=] is called on,
1135+
which would give ''15px''.
1136+
That's an unavoidable limitation of this situation.)
1137+
</div>
1138+
1139+
Issue: Do we want to try and figure out a way to have a mixin parameter
1140+
"remember" what element it was called on,
1141+
so it can resolve against that element consistently,
1142+
rather than require these workarounds?
1143+
I think that's inherently cyclic, tho--
1144+
imagine an ''em'' length used to set 'font-size' on a parent element.
1145+
1146+
1147+
1148+
10581149
<!-- Big Text: @contents
10591150

10601151
████▌ ███▌ ███▌ █ █▌ █████▌ █████▌ █ █▌ █████▌ ███▌
@@ -1292,6 +1383,43 @@ as that's a meaningful value that an ''env()'' could resolve to,
12921383
I guess?
12931384

12941385

1386+
<h4 id='dependent-envs'>
1387+
Element-Dependent Values</h4>
1388+
1389+
A [=scoped environment variable=] can be defined
1390+
(both explicitly, and implicitly via [=mixin=] parameters)
1391+
that require knowledge about the element the style is being applied to,
1392+
but ''env()'' can be used in locations that don't have an element context.
1393+
1394+
<div class=example>
1395+
For example, in this trivial example
1396+
an ''em'' value is passed to a mixin,
1397+
but the argument is then used in the ''@media'' rule inside the mixin.
1398+
1399+
<pre highlight=css>
1400+
@mixin --smaller(--size <length>: 800px, @contents) {
1401+
@media (width <= env(--size)) {
1402+
@contents;
1403+
}
1404+
}
1405+
h1 {
1406+
@apply --smaller {
1407+
margin: 1em 0;
1408+
}
1409+
}
1410+
</pre>
1411+
</div>
1412+
1413+
When this situation occurs,
1414+
if the value of the ''env()'' can be evaluated in its subsitution context at all,
1415+
it evaluates according to the normal rules for that context.
1416+
(For example, in a ''@media'', ''em'' values resolve against the initial font size,
1417+
rather than the font size of any particular element.)
1418+
1419+
If the value would be invalid in its substitution context,
1420+
it's instead replaced with the [=guaranteed-invalid value=].
1421+
(For example, ''var()'' isn't allowed in a ''@media''.)
1422+
12951423

12961424

12971425

0 commit comments

Comments
 (0)