Skip to content
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] Make min and max value optional in clamp() #9713

Closed
LeaVerou opened this issue Dec 15, 2023 · 8 comments
Closed

[css-values] Make min and max value optional in clamp() #9713

LeaVerou opened this issue Dec 15, 2023 · 8 comments

Comments

@LeaVerou
Copy link
Member

LeaVerou commented Dec 15, 2023

As we know, we added clamp() because doing clamping logic with min() and max() is counterintuitive.
However, this doesn't only apply when you have both a min and a max, it’s still counterintuitive when you only have one of two. I keep finding myself using clamp() with dummy min or max values so that I can only use it for max or min respectively, which not only adds cognitive overhead, but also pointless computation.

A nice little improvement could be to make the min and max values optional via none keywords:

Before:

<clamp()> = clamp( <calc-sum>#{3} )

After:

<clamp()> = clamp( [ <calc-sum> | none ] , <calc-sum> , [ <calc-sum> | none ])
Alternative syntax: Using empty tokens for the omitted argument
<clamp()> = clamp( <calc-sum>? , <calc-sum> , <calc-sum>? )

Note that this is different from clamp( <calc-sum>#{2, 3} ): we still need empty tokens for the missing arguments, otherwise we wouldn't be able to disambiguate. I.e. clamp(3rem, 10vh) would not be valid, it would need to be either clamp(3rem, 10vh, ) or clamp( , 3rem, 10vh).
If we go that route we'd also need to add an exception to require the comma with empty arguments, per normal grammar specification rules the comma would be omitted, making disambiguation impossible.

When I first posted this I thought going the empty token route would be ideal, as none seemed too verbose, but I now think the clarity hit is not worth it, especially if we take the editorial challenges into account.

Hopefully this is such a small change we may be able to wedge it in css-values-4.

Edit: Agenda+ after discussing it with @fantasai and @tabatkins — this seems like such an easy win and pretty uncontroversial so we could move forwards with hopefully very little call time.

@tabatkins
Copy link
Member

Yup, this makes a lot of sense. The confusion argument for introducing clamp() in the first place still applies when you're only clamping from one side, so making that easy seems like an obvious win.

(I'm pretty strongly opposed to the alternative "just omit the argument, but keep the comma in" syntax, as that violates our comma-elision rules, and those exist for a good reason. But the none syntax is great.)

@ByteEater-pl
Copy link

Why not just use max or min when you want to clamp from one side? What are the use cases for adding syntax to let clamp double as them? Code generation, perhaps?

@Loirooriol
Copy link
Contributor

@ByteEater-pl The idea is that min() and max() can be confusing, e.g. someone wants a calculation like var(--a) * var(--b) + var(--c) but enforcing a minimum of 0px. If they are thinking in terms of adding a minimum threshold they might be tempted to use min(), but actually they need max().

But I'm not sure if this proposal will really help much, people who misunderstands what min() does will probably use it anyway, and people aware of this "gotcha" can just use max() indeed.

@LeaVerou
Copy link
Member Author

LeaVerou commented Jan 5, 2024

@ByteEater-pl The idea is that min() and max() can be confusing, e.g. someone wants a calculation like var(--a) * var(--b) + var(--c) but enforcing a minimum of 0px. If they are thinking in terms of adding a minimum threshold they might be tempted to use min(), but actually they need max().

But I'm not sure if this proposal will really help much, people who misunderstands what min() does will probably use it anyway, and people aware of this "gotcha" can just use max() indeed.

Not necessarily. They might remember there is some weirdness around this, and this frees them from having to do the mental gymnastics. Or they may just reach for clamp() without considering min() or max() because they have internalized that that's what you use to introduce upper and lower bounds, and you use min() and max() when you need the minimum or maximum number among many. These are distinct use cases, and I'd argue using min() or max() for the former is actually a workaround, not a primary use case for min() and max().

@ByteEater-pl
Copy link

I'd bet most uses of max and min are with two arguments, so it does seem primary.

@tabatkins
Copy link
Member

The fact is still that max()/min() can be confusing to use, depending on what you're going for. If your intention is "use the largest of these two values", then max() is exactly what you need and completely intuitive. If your intuition is "use this value, but clamp it to a maximum of this second value", then the fact that you have to use min() for that is easy to get confused about. People regularly write that using max(), in my experience, and then are confused why that doesn't work.

So for the "use this value, but clamped above/below by this second value", using clamp() with only one bound makes a lot more sense.

@astearns astearns added this to Unsorted regular in Feb 2024 Agenda Feb 8, 2024
@astearns astearns moved this from Unsorted regular to Wednesday morning in Feb 2024 Agenda Feb 11, 2024
@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed [css-values] Make min and max value optional in `clamp()` , and agreed to the following:

  • RESOLVED: Add 'none' keyword for upper/lower bounds of clamp().
The full IRC log of that discussion <emilio> lea: the reason we introduced clamp() is that clamping with min() / max() is counter-intuitive, upper bound means min() and lower bound you need max()
<emilio> ... however author still need min() / max() when only have a lower bound or upper bound
<emilio> ... I found myself doing clamp(.., infinity) or such thing
<fantasai> ... suggestion in issue is to add a 'none' keyword
<emilio> ... so we discussed it in the issue, and it seemed like 'none' was straight-forward
<emilio> ... I even found author infographics about how confusing this is
<TabAtkins> +1 to this, as I said in the thread
<emilio> q+
<oriol> q+
<astearns> ack emilio
<TabAtkins> emilio: what's the reason for 'none' vs omission
<fantasai> fantasai: beause there's commas involved
<fantasai> TabAtkins: having an empty spot indicated only by presence of commas
<florian> q+
<fantasai> TabAtkins: is extremely awkward (and also violates comma elison rules)
<dholbert> scribe+
<dholbert> emilio (IRC): I was thinking you could clamp with 2 values
<dholbert> TabAtkins (IRC): which is which, upper vs lower
<astearns> ack oriol
<dholbert> emilio (IRC): then 'none' makes sense
<emilio> oriol: I kinda disagree with min() / max() being workarounds
<emilio> ... they mathematically are the same, but I agree there's some confusion
<emilio> ... not sure if this will completely solve it
<emilio> ... they may not realize that clamp(none) can help it
<emilio> ... this seems a pretty straight-forward generalization so seems fine, tho
<emilio> lea: when I said workaround it's a UX argument, not a mathematical argument
<astearns> ack florian
<emilio> ... when something is used for it's non-primary purpose it's a workaround
<lea> q+
<fantasai> florian: from utility point of view, setting both lower and upper bound to none is useless, but should we still allow it in the syntax?
<emilio> florian: setting both to none is useless
<lea> q-
<fantasai> TabAtkins: keep them both, because might be in a variable
<emilio> ... but should we keep them?
<fantasai> astearns: Seems we're all in violent agreement here
<fantasai> RESOLVED: Add 'none' keyword for upper/lower bounds of clamp().
<emilio> PROPOSAL: Allow none as firs or last arguments for clamp()
<lea> 🎉

@ByteEater-pl
Copy link

The CSS variables use case is convincing, I'm for. (It's like the code generation I mentioned, but built into the language.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Feb 2024 Agenda
Wednesday morning
Development

No branches or pull requests

5 participants