4 ms·
So I think I understand how this works? Correct me if I'm wrong... So I made this example: https://jsbin.com/meqibawotu/1/edit?html,css,output https://jsbin.co
by Rotten194 6y ago
So I think I understand how this works? Correct me if I'm wrong...
So I made this example: https://jsbin.com/meqibawotu/1/edit?html,css,output https://jsbin.com/meqibawotu/1/edit?html,css,output
We have two "toggle vars", `--is-hovered` and `--is-special`, which are triggered by a hover selector and a class, respectively, though they could be triggered by anything (like a media query or JS).
The "false" value for the toggle is "initial", so at the top I set:
div {
--is-hovered: initial;
--is-special: initial;
}
The first trick is that assigning a variable value as a single space token is valid according to spec (https://www.w3.org/TR/css-variables-1/#syntax https://www.w3.org/TR/css-variables-1/#syntax), making the var(...) usage substitute a single space. So if our variable should be "true", we use whatever method to set it to a single space:
div:hover {
--is-hovered: ;
}
div.special {
--is-special: ;
}
The second trick is that an invalid property value will fall back to the second argument of the `var()` function. So we first create a property that only has a valid value if the flag is true (a single space):
--hover-opacity: var(--is-hovered) 1.0;
If the div is hovered, `--is-hovered` is a single space, so the property value becomes:
--hover-opacity: 1.0; // note two spaces
If the div isn't hovered, `--is-hovered` is `initial`, so the property value becomes:
--hover-opacity: initial 1.0;
Which is invalid CSS!
We can then interpret this in our final opacity property:
--regular-opacity: 0.5;
--opacity: var(--hover-opacity, var(--regular-opacity));
If the div is hovered, the first argument is evaluated to:
--opacity: var( 1.0, var(--regular-opacity));
And since that's valid syntax, the second argument is short-circuited (ignored). However, if the div isn't hovered, then the opacity property is computed as:
--opacity: var(initial 1.0, var(--regular-opacity));
The first argument is invalid! So the property falls back to the second argument, and we get `var(--regular-opacity)`.
- James0x57 6y agoYEP! Absolutely nailed it. That's what's up! I've been calling it Space Toggle. It does all kinds of stuff beyond toggle though - the whole world of conditional logic is possible. You can combine them in any way, &&, ||, !, it's all possible. You can see some more of my examples here: https://twitter.com/James0x57/status/1283912525248069632 https://twitter.com/James0x57/status/1283912525248069632 https://twitter.com/James0x57/status/1283596399196680192 https://twitter.com/James0x57/status/1283596399196680192 https://twitter.com/James0x57/status/1282303255826046977 https://twitter.com/James0x57/status/1282303255826046977 The second version of augmented-ui is packed to the brim with it, I've been working on it for months :D
- teej 6y agoThis is really cool. How did you come up with this technique?
- James0x57 6y agoThanks! :D I wanted really badly to be able to do it, so I read the spec very carefully top to bottom a handful of times. And suddenly one day I just realized it. Dove right in and after a bit of progress, I discovered all the logic that was possible too. I had already been using spaces as a fallback value to do dynamic composition of standard properties ( https://twitter.com/James0x57/status/1233246818118533120 https://twitter.com/James0x57/status/1233246818118533120 ) so it wasn't too far off to combine it with the "initial" behavior that causes the entire var dependency tree to evaluate to initial, allowing fallback behavior from any point in the tree. :)
- karmakatze 6y agoObviously this is really cool. Also obviously this is a hack. I wouldn't expect this behavior to stay the same and not break such sites at any time. Also, clearly this was not the intention of the spec writers so it is syntactically weird and semantically in an unexpected place. So, while obviously cool, maybe this is not something one should rely on, right?
- tobr 6y agoCan I ask, what’s the reason for using the keyword “initial”? As I understand it it could be any string that doesn’t accidentally create a valid value?
- uxamanda 6y agoI was playing around with this here: https://jsbin.com/zebipenidi/1/edit https://jsbin.com/zebipenidi/1/edit and tried editing the keyword to other things. When I tried other strings (my name, "null", other CSS "words" like opacity) it broke. I wonder if this is because the initial variable definition needs to be valid css in order to be replaced?
- 6y ago
- James0x57 6y agoHeads up too, Firefox and Chrome both had trouble setting a var to space from the dev tools css panel. So if you play with this further, you may have to deal with that. I filed bugs to get it fixed though: https://bugzilla.mozilla.org/show_bug.cgi?id=1630488 https://bugzilla.mozilla.org/show_bug.cgi?id=1630488 (not fixed yet) https://bugs.chromium.org/p/chromium/issues/detail?id=1071296 https://bugs.chromium.org/p/chromium/issues/detail?id=107129... (fixed!) And minifiers hate it. lol
- Rotten194 6y agoCould you get around it with a special `--empty: ;` rule in root perhaps? Would potentially make things more clear, also.
- James0x57 6y agoYes, that would work. Then you just assign your properties to that var as long as you never inspect --empty on the root and you're good to test. Good thinking. Should be fixed in FF sooner or later though, I reported it in April
- rkagerer 6y agodear god, how did we get here (Neat trick I'm just weary of web languages that in practice feel like they're working against clarity)