Skip to content

Commit b8811a9

Browse files
Steinar H. Gundersonchromium-wpt-export-bot
authored andcommitted
Implement mixin parameters.
Applying a mixin now instantiates a “custom @env binding”, and all style rules that we create point back to that binding. (Bindings can point back to parent bindings, if we are applying mixins within mixins.) Like tree scopes, we send this pointer through the cascade so that we know what values env() should look up into when we apply the winning value. In other words, we substitute custom env() at computed-value time, like all other similar functions. This costs us a bit of extra RAM (~50 kB in a typical page), but we haven't seen any regressions on the style perftest. We generally follow the spec whenever it is clear, but there are some unknowns involved; in particular, the spec isn't clear on what happens if there are too few parameters and no defaults. We don't attempt to support mixins (and thus also custom env resolving) together with @Keyframe, @function, @page and a number of other at-rules that would cause edge cases. This should also build a reasonable foundation for implementing @env later, although the spec there is also a bit in flux. We also don't have any devtools support. Change-Id: I2188700352cb706184d3e0d7f85ab358d24dd936 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6935167 Commit-Queue: Steinar H Gunderson <sesse@chromium.org> Reviewed-by: Anders Hartvoll Ruud <andruud@chromium.org> Cr-Commit-Position: refs/heads/main@{#1517189}
1 parent 08861aa commit b8811a9

File tree

1 file changed

+159
-0
lines changed

1 file changed

+159
-0
lines changed

css/css-mixins/parameters.html

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@
2525
#e2b {
2626
@apply --m2(navy);
2727
}
28+
#e2c {
29+
color: fuchsia;
30+
@apply --m2();
31+
}
2832

2933
@mixin --m3(--my-color) {
3034
color: env(--my-color);
@@ -47,15 +51,104 @@
4751
color: green;
4852
@apply --m5(too-many-parameters);
4953
}
54+
55+
@mixin --m6(--my-color) {
56+
color: env(--my-color, navy);
57+
}
58+
#e6 {
59+
@apply --m6(green);
60+
}
61+
#e6b {
62+
@apply --m6;
63+
}
64+
#e6c {
65+
@apply --m6(invalid-color);
66+
}
67+
#e6d {
68+
color: env(--not-within-mixin, green);
69+
}
70+
#e6e {
71+
color: env(--not-within-mixin);
72+
}
73+
74+
@mixin --m7(--my-color) {
75+
color: attr(color-attr type(<color>));
76+
}
77+
#e7 {
78+
@apply --m7(green);
79+
}
80+
81+
@mixin --m8(--my-length type(<length>)) {
82+
font-size: 10px;
83+
--some-length: env(--my-length);
84+
}
85+
#e8 {
86+
@apply --m8(1.0em);
87+
}
88+
89+
@mixin --m9(--my-length type(length)) { /* Note the syntax error. */
90+
font-size: 10px;
91+
--some-length: env(--my-length);
92+
}
93+
#e9 {
94+
@apply --m9(1.0em);
95+
}
96+
97+
@mixin --m10inner(--inner-color) {
98+
color: env(--outer-color);
99+
}
100+
@mixin --m10outer(--outer-color) {
101+
@apply --m10inner(red);
102+
}
103+
#e10 {
104+
@apply --m10outer(green);
105+
}
106+
107+
@mixin --m11(--val, --true, --false) {
108+
color: if(style(--x: env(--val)): env(--true); else: env(--false))
109+
}
110+
#e11 {
111+
--x: a;
112+
@apply --m11(a, green, red);
113+
}
114+
#e11b {
115+
--x: a;
116+
@apply --m11(b, red, green);
117+
}
118+
119+
@function --f() {
120+
color: env(--my-color);
121+
}
122+
@mixin --m12(--my-color) {
123+
color: --f();
124+
}
125+
#e12 {
126+
@apply --m12(red);
127+
}
128+
}
129+
</style>
50130
</style>
51131
</head>
52132
<body>
53133
<div><div id="e1">This text should be green.</div></div>
54134
<div><div id="e2">This text should be green.</div></div>
55135
<div><div id="e2b">This text should be navy.</div></div>
136+
<div><div id="e2c">This text should be fuchsia.</div></div>
56137
<div><div id="e3">This text should be green.</div></div>
57138
<div><div id="e4">This text should be green.</div></div>
58139
<div><div id="e5">This text should be green.</div></div>
140+
<div><div id="e6">This text should be green.</div></div>
141+
<div><div id="e6b">This text should be navy.</div></div>
142+
<div><div id="e6c">This text should be black.</div></div>
143+
<div><div id="e6d">This text should be green.</div></div>
144+
<div><div id="e6e">This text should be black.</div></div>
145+
<div><div id="e7" color-attr="env(--my-color)">This text should be green.</div></div>
146+
<div><div id="e8">This text does not matter.</div></div>
147+
<div><div id="e9">This text does not matter.</div></div>
148+
<div><div id="e10">This text should be green.</div></div>
149+
<div><div id="e11">This text should be green.</div></div>
150+
<div><div id="e11b">This text should be green.</div></div>
151+
<div><div id="e12">This text should be black.</div></div>
59152
<script>
60153
test(() => {
61154
let target = document.getElementById('e1');
@@ -72,6 +165,11 @@
72165
assert_equals(getComputedStyle(target).color, 'rgb(0, 0, 128)');
73166
}, 'Mixins can be called multiple times with different parameters');
74167

168+
test(() => {
169+
let target = document.getElementById('e2c');
170+
assert_equals(getComputedStyle(target).color, 'rgb(0, 0, 0)');
171+
}, 'Too few parameters and no default ignores mixin');
172+
75173
test(() => {
76174
let target = document.getElementById('e3');
77175
assert_equals(getComputedStyle(target).color, 'rgb(0, 128, 0)');
@@ -86,6 +184,67 @@
86184
let target = document.getElementById('e5');
87185
assert_equals(getComputedStyle(target).color, 'rgb(0, 128, 0)');
88186
}, '@apply with too many parameters is ignored');
187+
188+
test(() => {
189+
let target = document.getElementById('e6');
190+
assert_equals(getComputedStyle(target).color, 'rgb(0, 128, 0)');
191+
}, 'Fallback is ignored if argument is given');
192+
193+
test(() => {
194+
let target = document.getElementById('e6b');
195+
assert_equals(getComputedStyle(target).color, 'rgb(0, 0, 128)');
196+
}, 'Fallback is used with no parameter and no default');
197+
198+
test(() => {
199+
let target = document.getElementById('e6c');
200+
assert_equals(getComputedStyle(target).color, 'rgb(0, 0, 0)');
201+
}, 'Fallback is not used on other errors');
202+
203+
test(() => {
204+
let target = document.getElementById('e6d');
205+
assert_equals(getComputedStyle(target).color, 'rgb(0, 128, 0)');
206+
}, 'Fallback is not when outside mixin');
207+
208+
test(() => {
209+
let target = document.getElementById('e6e');
210+
assert_equals(getComputedStyle(target).color, 'rgb(0, 0, 0)');
211+
}, 'Invalid when no fallback and outside mixin');
212+
213+
test(() => {
214+
let target = document.getElementById('e7');
215+
assert_equals(getComputedStyle(target).color, 'rgb(0, 128, 0)');
216+
}, 'env() can be accessed from attributes');
217+
218+
test(() => {
219+
let target = document.getElementById('e8');
220+
assert_equals(getComputedStyle(target).getPropertyValue('--some-length'), '10px');
221+
}, 'env() resolves typed parameters');
222+
223+
test(() => {
224+
let target = document.getElementById('e9');
225+
assert_equals(getComputedStyle(target).getPropertyValue('--some-length'), '');
226+
assert_equals(getComputedStyle(target).fontSize, '10px');
227+
}, 'env() refuses illegal syntax parameters, but does not fail entire mixin');
228+
229+
test(() => {
230+
let target = document.getElementById('e10');
231+
assert_equals(getComputedStyle(target).color, 'rgb(0, 128, 0)');
232+
}, 'env() can access parameters from outer mixins');
233+
234+
test(() => {
235+
let target = document.getElementById('e11');
236+
assert_equals(getComputedStyle(target).color, 'rgb(0, 128, 0)');
237+
}, 'env() works inside if, in condition and true branch');
238+
239+
test(() => {
240+
let target = document.getElementById('e11b');
241+
assert_equals(getComputedStyle(target).color, 'rgb(0, 128, 0)');
242+
}, 'env() works inside if, in condition and false branch');
243+
244+
test(() => {
245+
let target = document.getElementById('e12');
246+
assert_equals(getComputedStyle(target).color, 'rgb(0, 0, 0)');
247+
}, 'env() within a function should not see parameters from a calling mixin');
89248
</script>
90249
</body>
91250
</html>

0 commit comments

Comments
 (0)