-
Notifications
You must be signed in to change notification settings - Fork 669
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
[css-values] Iverson bracket functions: if(), media(), supports(), defined() #4731
Comments
Desugarings of
(note The problem are comparisons with NaN or infinity. |
Perhaps, CSS would be better suited with a generic if(A < B, C, D) = lesser(A, B, C, D) =
if(B > A, C, D) = greater(B, A, C, D) =
if(A >= B, D, C) =
if(B =< A, D, C) =
compare(A, B, C, D, D) =
compare(B, A, D, C, D)
if(A >= B, C, D) =
if(B =< A, C, D) =
if(A < B, D, C) = lesser(A, B, D, C) =
if(B > A, D, C) = greater(B, A, D, C) =
compare(A, B, D, C, C) =
compare(B, A, C, D, C)
if(A > B, C, D) = greater(A, B, C, D) =
if(B < A, C, D) = lesser(B, A, C, D) =
if(A =< B, D, C) =
if(B >= A, D, C) =
compare(A, B, D, C, D) =
compare(B, A, C, D, D)
if(A =< B, C, D) =
if(B >= A, C, D) =
if(A > B, D, C) = greater(A, B, D, C) =
if(B < A, D, C) = lesser(B, A, D, C) =
compare(A, B, C, D, C) =
compare(B, A, D, C, C)
if(A != B, C, D) = compare(A, B, C, D) =
if(B != A, C, D) = compare(B, A, C, D) =
if(A == B, D, C) = equal(A, B, D, C) =
if(B == A, D, C) = equal(A, B, D, C)
if(A == B, C, D) = equal(A, B, C, D) =
if(B == A, C, D) = equal(B, A, C, D) =
if(A != B, D, C) = compare(A, B, D, C) =
if(B != A, D, C) = compare(B, A, D, C) (The order and fallback of the comparison function parameters could probably be optimized more.) |
Considering that there are already tokens for stuff like With abs/sign, as demonstrated above, you can already do most everything proposed here with css as specced, so this is about making it easier to do those things (and thus harder to accidentally do it the wrong way), making it clearer when you do those things, and possibly adding in a little extra that can't be done yet—or at least polishing the edge cases so they're not as sharp. |
Iʼm not particularly fond of If only the first parameter was mandatory, the second could default to zero, the third to the first and the fourth to the second. |
So if you have X and you want to add Y when
With if() it's a bit more straightforward
(I'm assuming that If I messed something up but that just proves my point that it's too difficult 😄 |
If we want boolean functions, I think it may be clearer if we consider a new type
This wouldn't be a numeric value (I guess it could be a CSSKeywordValue, but I don't know much about Typed OM), so things like A Operators like Then, So your example would become :root {
--dur: if(media(prefers-reduced-motion), 5s);
} This makes it more clear that we want to set Probably, if(if(A > B, C > D, E > F), 10px, 20px);
/* same as */
if((A > B && C > D) || (!(A > B) && E > F), 10px, 20px); |
So you couldn't do |
I don't know. Opening the door to that may introduce some problems. For example, IMO it would seem unexpected if stretching is allowed with So we should probably change css-align to accomodate conditionals that end up resolving to |
would that also create problems with using % in a conditional for setting width in something whose parent is intrinsically sized? I'm not sure when all that stuff gets worked out. |
I would expect this to be handled by https://drafts.csswg.org/css-sizing/#percentage-sizing. When calculating intrinsic contributions, a cyclic percentage may be treated as zero or the whole expression may be treated as |
Thanks for the link. Are keywords in general dangerous? Could I'm fine with it being purely numeric but it would be nice if you could write, say, |
Note that And yes, keywords seem more problematic, e.g. Possibly we could add some constraints, like restricting the properties that accept |
Is that an example from a realistic use case or just a strawman? Actually, another possibility would be some kind of ternary operators inside
Some of these are of course very unfamiliar from outside CSS (especially from JS), but they could be appropriate nevertheless. |
I don't expect much day-to-day code to have as complicated a condition, no. Logical conditions would be useful in real code for stuff like I expect they'd get the most use in css frameworks that define a lot of stuff with custom properties that act as knobs. At some point, I'd hope that we could define reusable custom calc functions directly in css and I imagine libraries of such functions could involve somewhat complicated conditionals. Cf. my comment: w3c/css-houdini-drafts#857 (comment) |
Does Does If bool is added, there are a lot of attributes that are either "true"/"false" or have bool-ish definitions and it would be handy to be able to do things like |
Kind of, but they would return a boolean, which probably most math functions (like
Yes, that's what I was thinking.
I wonder whether some string operations could be useful too, like checking if an attribute value starts, ends or contains a substring. |
If bools are an ordinary type (not special syntax used in For strings, to keep things consistent, I guess |
I do suspect we might add a bool type at some point for these kinds of purposes, yeah. I'm inclined to currently put this on the side of "make sure that custom functions can handle this case so |
If everything is in place except |
More or less, yeah. |
Is there much use for the bool type if you can't do conditionals (without js)? |
I propose three mathematical functions inspired by Iverson bracket notation — if(p), media(q), supports(s) — that can only be used within calc() and always return either 0 or 1. This is useful for concisely toggling terms on or off in an expression, like
width: calc(500px + 10px*media((width > 800px)))
.media() is simple to define by example:
is equivalent to
and similarly for supports(). If the media or feature query match, evaluate to 1. If it fails to match or is not recognized, evaluate to 0.
if() is similar but work on expressions logical and comparative expressions involving var(), env(), and attr(), like:
I am leaving this somewhat loosely defined. There are a lot of cases to consider I'm not sure what the best solution is for all of them. Should non logical/relation expressions be allowed? That is, should
if(2*var(--x))
evaluate to 1 if it the inner expression is computed to be nonzero or does there need to be an explicit comparison? An if() that contains an undefined var/env or unset attr should evaluate to 0 but should there also be another bracket function likedefined(var(--x))
? Should non-numbery variables always cause evaluating to 0 or shouldif(var(--state) = paused)
be allowed?For defined purely numeric cases, if() can be emulated with inventive combinations of arithmetic and min, max, clamp, abs, sign, round, mod, and rem but it gets fairly nasty even for relatively simple cases and even if you follow what's going on it lacks readability.
#3455 was a previous attempt at an if(). It was deemed too powerful. It was different from the current proposal in two ways:
I suspect that 1 is the entirety of the argument for it being too powerful, though I am unsure. If this is case, this proposal can be extended by dropping the requirement that these must be in calc() and giving them optional parameters so that
And possibly similarly for media and supports, though that could require disallowing "," within the media query itself. Although note that if nonzero is considered true then you could leave media() and supports() unchanged and use
if(media(q), then, else)
.The text was updated successfully, but these errors were encountered: