-
Notifications
You must be signed in to change notification settings - Fork 706
[css-variables] Should var(var(--x))
work?
#11144
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I feel like there should be a problem with this proposal ... but I can't think of one. I assume this would then extend generally to all substitution functions, so e.g. both |
Note this implies that you can't just build the full directed dependency graph before resolving .foo {
--a1: --b2;
--a2: var(var(--a1));
--b1: --a2;
--b2: var(var(--b1));
}
|
Also |
Yes, this would be a generic behavior for all arbitrary substitution functions.
Hm, that's certainly a bit more annoying. @andruud, does that alter your opinion at all? I could see us specifically requiring But maybe it's fine and we can just do a later check. The effects of a dependency cycle don't kick in until resolution time, anyway.
|
We don't rely on "statically" figuring out the dependency graph in Blink. It seems pretty hard to do that already, for example:
We should check other implementations. @Loirooriol, do you know if there's an impl. that needs to build the dependency graph early? |
I don't know, I just tried to think about possible implications. |
Another wrinkle here: currently, if a property contains a substitution function, it's always considered valid at parse time (and will be considered actually valid or IACVT at computed-value time), unless the substitution function itself is grammatically invalid. That's the only way to have a var-containing property actually get considered invalid at parse time. With this change, the concept of "invalid at parse time" becomes harder to reach. Unless we add some even more special behavior (which I'd prefer not to), having a var() in the fallback will cause the outer var() to not be syntax checked until later. That is: .invalid-child {
color: var(--foo, var(1));
/* today: invalid at parse time (due to `var(1)`)
after change: still invalid at parse time, same reason */
}
.invalid-parent {
color: var(1, var(--foo));
/* today: invalid at parse time (due to `var(1, ...)`)
after change: valid at parse time, IACVT later */
}
.unknown-invalid {
color: var(var(--foo));
/* today: invalid at parse time
after change: valid at parse time, might be valid or IACVT later, depending on --foo value */
} This is a lot more arbitrary than I first thought when I wrote that invalidity requirement. I think we should drop it, and make the presence of a substitution function just always treat the property as valid, regardless of what's inside its parens. This would make all of the above be valid at parse time, then the first two will be IACVT (and the third may or may not be). This would mean that This would only be a behavior change for code that's currently invalid; we usually consider this kind of behavior change to be safe to make by default. |
So the actual processing model then becomes:
This is also more forwards-compatible. Today, you could write Similarly, if authors are using custom properties today to shuttle around random non-CSS values (for example, JS...) and those values contain something that happens to look like a substitution function (like |
That mostly makes sense, but I don't understand why (4) and (5) are needed, and what exactly what you're describing here. Are you saying that for:
the computed value of |
@andruud That is already the case, unless |
4 is necessary because the timing of substitution of With this change, you won't always be able to do that, so you'll have to do the substitution eagerly, as part of processing the outer 5 is a consequence of that, just removing the currently specified behavior that the presence of a guaranteed-invalid value immediately makes the property IACVT.
Right, like @ExE-Boss says, that's luckily already the case; see https://drafts.csswg.org/css-values-5/#invalid-substitution. Here's a testcase demonstrating it: <!DOCTYPE html>
<style>
#parent {
--x: green;
}
#child {
--x: var(--unknown);
background: var(--x);
}
div { padding: 20px; margin: 20px; border: thin dotted; }
</style>
<div id=parent><div id=child></div></div> (The #child ends up without a background color, because --x is invalid on it. It doesn't inherit the I think, to be a little more specific, the rule would be that if a substitution function fails to parse, it's substitutes as itself, but with all of its tokens "marked as meaningless" - meaningless tokens don't have any behavior and don't match any grammar except the "anything goes" ones like So, yeah, the computed value will be This has a few effects, all of which are good imo:
|
@ExE-Boss Ah, right, I forgot that we changed to that behavior in #6006. (I even changed it myself ...) That's all good, then.
That's not true. We (currently) have to resolve any var() in the fallback to look for cycles, even when the fallback is not taken. However, the fallback being (or containing) guaranteed-invalid has no effect unless the fallback is taken.
It is already the case.
This sounds awful, and likely a non-starter. But I also don't see why it's needed. It's possible that we actually agree on how this should all work, but with entirely different mental models. I need to process what you wrote a bit more and see if I can come up with an alternative way to describe the behavior ... |
lol. Well, the requirements I'm trying to satisfy are, roughly in decreasing priority:
There's many ways to satisfy (1), but I think (2) is a lot stricter, and (3)/(4) basically force the same requirements. Let me rephrase the proposal a bit, maybe you'll like it better this way:
This does change the serialization of properties that include a failing substitution function; currently they're specified to be the empty string. We could probably special-case that to preserve the behavior specifically for serializing a custom property (while substitution continues using the actual values, which will serialize as a non-trivial string). |
Bumped into this today while trying to implement the Arbitrary Substitution Function concept. I don't know how useful my opinion is but I'll add it anyway. 😅
|
Per the resolution in #11500, which is now editted into the spec, |
The Variables spec is currently not entirely clear whether
var(var(--x))
is intended to work. As an example:Should this be valid, resulting in
color: var(--color);
, and ultimatelycolor: green;
?Chrome's implementation, iiuc, currently allows nested var() references only in the
<declaration-value>
part, because that chunk isn't interpreted at all - they're processed as part of fallback processing. Per Variables (now Values), you have to verify that the var() is syntactically valid at parse time; our engineers interpreted that as "you must fully satisfy the specified grammar". This isn't an unreasonable position, but it does mean we're slightly limited in how var() can be used.The larger issue is that this has knock-on effects for other arbitrary-substitution functions. For example, in
if()
, if we apply the same criteria, it's allowed to use avar()
in the value of a clause (which is a<declaration-value>
, so avar()
there just isn't interpreted at parse-time), but not as part of the test (which has a specific grammar);--test: media(width < 600px); color: if(var(--test): green)
would be invalid. I think that's pretty surprising, and authors would run into it and complain.So, I believe we should fix up the definition a bit to allow for nested var() delaying the syntax checking of outer var()s.
/cc @LeaVerou @andruud
The text was updated successfully, but these errors were encountered: