Open philipwalton opened 9 years ago
Within a custom property's value, only var()
values are expanded. Everything is kept literal, waiting for processing by something else (substitution into another property via var()
, processing via JS, etc).
So using @apply
in a custom property bag does nothing at declaration time. Upon use (via an @apply
in another rule), the value of the custom property is subbed into the style rule and processed. At that point, the inner @apply
is processed, triggering another substitution. Both the outer and inner @apply
s use the value of the given custom property on the invoking element.
If you want to build a custom property bag out of multiple other custom property bags at declaration time, use var()
:
.parent {
--foo: {
color: red;
var(--bar);
};
--bar: {
background-color: white;
};
}
.child {
@apply --foo;
/* gets "color: red; background-color: white;" */
}
Merging in a child (like your last example) can be accomplished, but it's a little tricky until we get the ability to refer to the parent's variable value. You'd just write something like:
.parent {
--styles: { font-family: monospace; };
}
.child {
--styles: { var(parent --styles); color: red; };
}
.grandchild {
@apply --styles;
/* gets "font-family: monospace; color: red; } */
}
This is the same problem as building up an "accumulating" variable for normal use - you need something like --indent: calc(20px + var(parent --indent));
to make it clean.
To do it today, you instead need to change the variable name as you go down the tree, such as appending a generation counter to the var name, so you're not self-referencing. This is tricky and error-prone, obviously. I'm waiting until variables finish getting implemented and used before doing Variables Level 2 with this ability.
THAT SAID, I might change the @apply
behavior so that it gets substituted in at declaration time, like var()
does. The behavioral difference isn't intentional; there's just as much call for something like --shadow: var(--shadow-color-at-use-time) 2px 2px;
, so Variables level 2 will have some ability to declare that a var()
is substituted "late", at use-time, rather than at declaration time. Having @apply
work the same way - substituted at declaration time by default, and at use-time by request - is probably best for authors. And it means you don't have to remember the weirdness of using a var()
in a declaration context, like my examples above do - they'd instead both be written with @apply
, which I think feels much more natural, as it keeps the "var()
is for values, @apply
is for declarations" concept consistent.
For example, imagine inside
<my-element>
you have the following style declaration:I've been experimenting with the
@apply
feature in Polymer and, when composing elements, I quickly found myself wanting to have the composing element set some custom property values yet still allow for parent elements to override them. As far as I can tell, that's not supported (at least not explicitly) in this proposal (Polymer fails when trying this).Conceptually related, it's not clear to me whether custom property bags operate as a merge (like they do on elements) or as an override.
For example, consider the following HTML structure and CSS rules:
Is the text red and monospaced, or is it just red because
--styles
was overriden in.child
?What I suspect is that the declarion is overridden, and if so, that could be an argument in favor of custom pseudo-elements as they could more gracefully (and predictably) handle merging of properties via the cascade.