-
Notifications
You must be signed in to change notification settings - Fork 689
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] Re-adding min() and max()? #544
Comments
So, for “locks”, selector {
property: /* $min_value ≤ */ $fallback_value /* ≤ $max_value = $min_value + $max_increment */;
}
@media (min-width: $min_vw) and (max-width: $max_vw) {
selector {
property: calc( $min_value + $max_increment * (100vw - $min_vw)
//* ——————————————————— */
($max_vw - $min_vw) );
}
}
@media (max-width: $min_vw) {
selector {
property: calc( $min_value + 0 );
}
}
@media (min-width: $max_vw) {
selector {
property: calc( $min_value + $max_increment /* = $max_value */ );
}
} would become selector {
property: /* $min_value ≤ */ $fallback_value /* ≤ $max_value = $min_value + $max_increment */;
property: calc( $min_value + $max_increment * min( (100vw - $min_vw)
//* ——————————————————— */
($max_vw - $min_vw), 1) );
} right? I wonder if authors would also find good use for |
I proposed a map() function that allows for min and max sizes as well as easing and interpolation of more than just length units: #581 I think this would be a much more versatile approach, especially with things like variable type, where min() and max() might not work. |
People have shared with me examples of how Since |
It's generally good API design practice to have shortcuts for commonly needed things, otherwise you end up with clunky, verbose APIs that are a pain to use for anything. I will not discuss whether what you're proposing is a good idea or not here, partly because I haven't thought about it much. However, even if it is, using |
I wonder whether {
min(100px 10em 10vw) calc(min(100px 10em 10vw));
min(100px, 10em, 10vw) calc(min(100px, 10em, 10vw));
100px < 10em < 10vw calc(100px < 10em < 10vw);
100px << 10em << 10vw calc(100px << 10em << 10vw);
max(100px 10em 10vw) calc(max(100px 10em 10vw));
max(100px, 10em, 10vw) calc(max(100px, 10em, 10vw));
100px > 10em > 10vw calc(100px > 10em > 10vw);
100px >> 10em >> 10vw calc(100px >> 10em >> 10vw);
} This works well for minimum and maximum where you can compare one pair after the other – CSS has only {
calc(a | b); /* median */
calc(a = b); /* arithmetic mean, average */
calc(a # b); /* either count or mode (work) or geometric mean (doesn’t work) */
calc(a ~ b); /* round $a to an integer multiple of $b */
calc(a _ b); /* floor, round down $a to an integer multiple of $b */
calc(a ` b); /* ceiling, round up $a to an integer multiple of $b */
calc(a ^ b); /* $a to the power of $b */
calc(a % b); /* $a modulo $b, or $a integer-divided by $b, or remainder of $a/$b */
calc(a : b); /* one of the other from the line above */
/* … */
} |
I believe we can't add angle brackets for some syntax reason, which is why we used |
Erm, MQ4 uses angle brackets: https://drafts.csswg.org/mediaqueries-4/#mq-range-context |
The reason for avoidance of The advantages of |
|
In mathematics, though, Pairing the angle brackets, i.e. {
max(a b c) calc(max(a b c))
<a b c> calc(<a b c>)
a > b > c calc(a > b > c)
min(a b c) calc(min(a b c))
>a b c< calc(>a b c<)
a < b < c calc(a < b < c)
abs(a) calc(abs(a))
|a| calc(|a|)
round(a, b) calc(round(a, b))
[a]b calc([a]b)
[a]~b calc([a]~b)
a ~ b calc(a ~ b)
floor(a) calc(floor(a)) ⌊a⌋
[a]_ calc([a]_)
_a_ calc(_a_)
(a _) calc(a _)
ceil(a) calc(ceil(a)) ⌈a⌉
[a]` calc([a]`)
[a]^ calc([a]^)
`a` calc(`a`)
^a^ calc(^a^)
(a `) calc(a `)
} |
Please use function syntax. Readability is much more important than saving a few key strokes. |
Readability is my primary goal, too! It’s so easy to get lost in the parentheses of nested functions. |
To pretty much everybody who has ever seen that symbol, My objection against |
It's a bit like default/fallback values in Lua etc.: Takes some time to get used to, but makes sense. Anyway, I'm not feeling strongly about this, just wanted to provide some thinking outside the box. |
Symbols and icons aid usability when they follow an established convention and are recognizable. If they have to be memorized and make no intuitive sense, then they just make the learning curve steeper. Think of those apps that use a long toolbar of icons that have no obvious meaning. I would be strongly opposed to any of these notations for this reason. |
It can also be just about impossible to google a new syntax using symbols, making it hostile to novice authors. |
RESOLVED: Add min() and max() to css-values-, valid within and without calc(), accepts N calc() expressions as arguments. |
I’m seriously considering to propose
PS: @LeaVerou is confusing lexicon and syntax of icons. My sub-proposal still had angle brackets meaning larger and smaller, it just took advantage of CSS’s feature of not needing a boolean type in property values – did someone ever propose |
One issue per report, @Crissov. |
Small question as an author: what would be the proposed syntax for authors declaring lower and higher bounds? Nesting min and max?
I looked up the |
@fvsch I don't like that much nesting, but how about this (proposed syntax enhancement):
Or this:
Or maybe even this:
If you didn't want a min, you could put a zero in that spot. If you didn't want a max, you could just leave it off, along with its preceding comma. |
The proposed syntax is that One of the issues with adding a minimum and a maximum constraint to a value (as in #544 (comment)) is that there are two options to how to process them, which produce different results when the minimum is greater than the maximum. CSS generally treats the minimum as winning, so that the standard CSS way to enforce a minimum and maximum constraint on a value is But, in general, the functions allow you to combine values in other ways. For example, you can write things like The further syntax proposal for allowing these to appear at top level is that, while these are functions that conceptually live inside of |
@bradkemper I really like your proposed syntax however I don't think it would give complete control over the rate of scale. You would not be able to pick the viewport range. I wrote a whole lot more of my ideas relating to this discussion in an article: https://madebymike.com.au/writing/interpolation-without-animation/ and updated the map proposal. |
One could also add What this function does is return examples: width: clamp(500px, 10px, 999px); //returns 500px
width: clamp(1px, 100px, 9999px); //returns 100px
width: clamp(999999999px, 10px, 1000px); //returns 1000px
width: clamp(1px, 99999px, 10px); //returns 10px
width: clamp(1px, 99px, 99px); //returns 99px It doesn't matter whether The behavior works slightly different when clamping angles, though, so beware that. |
Isn't that just a shorthand notation?
|
I'll +1 this, I have a function clamp(min, mid, max) {
return Math.min(Math.max(min, mid), max)
} Example: https://codepen.io/tomhodgins/pen/ALWaVr After experimenting around with this sort of clamping functionality — where you give a preferred (usually scalable) unit in the middle, capped on either end by a lowest and highest limit — it has been really useful for typography. I'd love to see a |
I do agree that It also gives you a consistent answer to which wins if the two aren't in proper order, min or max - we'd match standard CSS practice and have min win. (If you want max to win, you can manually write a nested min()/max() expression with max() on the outside.) I also agree that the argument order Finally, it avoids the significant confusion (at least, that I experience) when using min()/max() directly, where you have to put the upper value in the min() function, and the lower value in the max(). That is, you implement a min-* effect by using the max() function, and vice versa. This always confuses me! |
The differences with
The names can be changed, maybe |
out-of-order clamping (that is, interpret the smaller one as min and larger one as max, regardless of how they were specified) can definitely be done, but it doesn't match current CSS behavior of min/max pairs. Like "max wins", it can be done manually (where you see the minvalue in the normal expression, instead use (Alternately, just waiting for custom functions could let us handle this. Since this can be done as a simple rewrite of the expressions, it might look something like:
) Angle clamping can potentially be given special behavior, but can you elaborate on what your preferred behavior is? I can't understand it from your brief description. Color clamping is a whole other kettle of fish, with lots of different behaviors one might want to use. |
If you give two random angles, there are two possible arcs described. Unless the angles are diametrically opposite (in which case I guess the function would simply return For instance, if you pass 0° and 90°, there are two arcs: one is 90° and the other 270°. Thus, when clamping an angle, say you just passed as parameters 0° for the This seems intuitive, and behaves just like the previous example, until you look at things like passing 270° and 0°. You still want to clamp to the the smaller arc of 90°, not the greater arc of 270°. Therefore, passing 110° as Things also get confusing when you start providing things like 3600° (or any value bigger than 360°, really), but the trivial solution is to just mod it to 360° which would make 3600° equal to 0°. Negative angles also get trivially converted to their positive counterparts. Alternatively there could be an |
As for color clamping, I guess one could just use RGB() and clamp inside the parameters for maximum control |
That's if you treat the angles as just points on a circle, where spinning 360deg gives you the exact same point. We don't do that in CSS - angles are numbers like anything else; 0deg and 360deg might map to the same direction in the end, but they're treated as completely distinct values otherwise. (So you can, for example, animate from So in CSS, if you give 0deg and 90deg, there's only one "arc", going from 0 and 90. Between 0deg and 270deg there's only one "arc", going from 0 to 270. If you want the "small" arc in that second case, use the angles property: specify -90deg and 0deg, or 270deg and 360deg. This does suggest that there might be justification for modding angles, for when 0deg and 360deg really are exactly the same for a given application. But it shouldn't be built into clamp(). |
Should this be closed, given 371d0a1 ? @tabatkins |
Still needs a testcase. Also I'd like to split out the clamp() proposal to a separate thread. |
@tabatkins Is there a thread for the |
just gonna throw this here:
|
There are implementation implications. Currently, implementations can internally reduce any calc to an array of coefficients. (Element dimensions, font size, device orientation might change during an animation, so a calc can't simply be represented as a number of pixels.) This proposal requires a slow path of general expression evaluation during each frame's style calculation. Suppose we have animation between At 75% progress, the result is |
@ewilligers Can’t this still be reduced to an array of coefficients, i.e. If a,b change during the animation, you can pre-calculate that. |
That's a nested structure, which can be arbitrarily nested, not a flat array. (Aka a sum of simple values.) But we already need to support this sort of arbitrary structure for the unit algebra that the WG resolved on and which is already specced in Typed OM. |
@tomasdev I don't get it… |
Perhaps now that Values 3 has gone to CR it's time to reconsider adding
min()
andmax()
back into Values 4?Authors are doing extremely weird hacks with
calc()
to emulate them infont-size
andline-height
, which they call "CSS locks". If you google CSS locks you will see how widespread these hacks are becoming, indicating a clear author need.Furthermore, as CSS variables become more widely used, the need for
min()
andmax()
will become even greater. I recall some of the issues that made us drop them 6 years ago can now be solved with the invalid at computed value time concept that Variables introduced.The text was updated successfully, but these errors were encountered: