-
Notifications
You must be signed in to change notification settings - Fork 642
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-4] How to interpolate min/max/clamp? #4082
Comments
Suppose we have a start keyframe Suppose we initially have container width If we read the computed style at 50% progress, the result changes from Informally, we might think of the start frame "used value" changing from |
One option is to introduce an Note that this was decided for transform list animation as well for similar reasons, there's no way to describe an interpolation for all possible computed values using the same value syntax due to the implicit branching on layout output (after resolving percentages). |
My preference would be to interpolate the individual parts of the function. So, if you are transitioning from This would be consistent to what happens if you have a fixed For the functions, this method of interpolation could be extending to work when transitioning from a simple dimension to a min/max/clamp function. The simple dimension could be replaced by a matching function with all the parameters set to the original value, and transitioned from there. E.g., when transitioning from For transitioning from one function type to another (e.g., from a min() function to a max() function), they would need to be treated as separate terms combined in a calc expression. So, the mid-point between |
@AmeliaBR So if you want to interpolate function parameters instead of function results, does it meant that the half point between IMO this kind of things seem nice for simple cases but can get complicated and very inconsistent. So while I do think it's a valid usecase, maybe it would be better to do it using custom props. I believe this is supposed to work if #el {
transition: --param 1s;
--param: 0%;
width: min(5em, var(-param));
}
#el:hover {
--param: 100%;
} |
@Loirooriol My suggestion was specifically for min/max/clamp. I hadn't thought about extending the same logic to the trigonometric or power functions. For the examples you gave, there's no reason not to simplify the math functions at computed time, prior to interpolation. That said, there are trig functions that couldn't be simplified at computed value time, like |
Using registered custom properties for animating individual expression parameters sounds like an appropriate solution to me. I think it's a bit too expensive to have the browser do it by default. |
I'm not sure it's any more expensive than the alternative. Compared to calculating layout, interpolating numbers is easy, even if you have a list of them that need to be compared or combined at the end. If we interpolate used values, that means that you can't do the interpolation until after layout. If anything that affects layout is also changing (as in Eric's example), then you can't compute the interpolated value at a given time without doing layout for that point in time. |
The problem isn't interpolating numbers, it's matching up numbers across two expression trees so that you know what should interpolate with what. That can get expensive. |
IMO simply allocating and updating such a data structure is the expensive part. The actual interpolation/evaluation math is probably minuscule. |
We already have rules for upgrading simple expressions to more complex ones in the procedure for interpolating percentages and dimensions, so that shouldn't be an issue. Currently, if you interpolate between a percentage and a length, there is an initial step where both are converted into calc expressions: Yes, for interpolating more complex The interpolation doesn't apply to used values and it doesn't need layout. All that said, after spending a lot of time today trying to sketch out how a similar approach could work with comparator functions, I am now convinced that interpolating values inside the functions wouldn't work. The first issue is that the order of values in a max or min function is arbitrary. Pairing up gives you different results depending on whether you sort them by unit type or not:
Similarly, you can't simplify additions of different comparator functions on a term-by-term basis:
So, my revised suggestion is that any math function needs to be treated as an opaque algebraic term, that can't be interpolated inside of itself. In other words, when interpolating from
More generally, you replace each unique function with a variable. Transitioning between two non-identical functions results in an expression of the form The same approach would apply to the trig and power functions. This approach ensures that the interpolation is always linear, and gives the same result regardless of whether you are able to simplify to a number before or after the linear interpolation:
|
Yes, I agree with this approach (interpolation is basically just treating each side as opaque); I spent some time thinking on it yesterday and came to the same conclusion, but didn't have the time to write it down yet. ^_^ I don't think the caveat about "non-identical functions" needs to be there. All math interpolation would just be scaling and summing the two endpoints, it's just that algebraic simplification is allowed to occur. The old "line up the components and interpolate each" is identical in result to this, since the components all combine linearly as well. |
Sticking with linear interpolations only for dimension animations keeps things simple for web/browser developers. Registered custom properties enables non-linear interpolation via function parameter interpolation. I'm in support of this. |
Yeah, that's just another optional simplification. It would only be relevant if you're talking about comparing top level expressions, where you need to know if you're actually transitioning the value at all, or if before and after have identical computed values.
Yes, that is definitely another argument for keeping the default behavior simple: the author can always force a different interpolation behavior by interpolating a variable instead of the complete expression, as Oriol showed above. |
The CSS Working Group just discussed
The full IRC log of that discussion<dael> Topic: How to interpolate min/max/clamp?<dael> github: https://github.com//issues/4082 <dael> AmeliaBR: I agenda+ it, though thinking of it for next week. <dael> AmeliaBR: We're starting to get consensus, at least TabAtkins and I and Alan C agree <dael> AmeliaBR: We have new mask functions including these functions. We don't have anything that defines how work in animations and transitions. They generally work on computed values and these functions exist at computed time so need to define how to interpolate <smfr> s/mask/math/ <dael> AmeliaBR: Proposal is that interpolation would be a linear interpolation of the terms where the functions on the initial side of interpolation are scaled to to multiplied by 0 and on the result side the scaled up from 0 to 1. Intermediary result is the sum of those terms <dael> AmeliaBR: Important benefits of the approach is you can define the intermediary value as a computed value without needing to sub in values from layout. And you can do mathematical simplification and it won't change result <dael> AmeliaBR: If author wants different interpolation like changing power and want power interpolated instead of results they can do by custom properties and interpolate the custom prop rather then final mathematical expression <dael> Rossen_: Other comments or thoughts? <dael> AmeliaBR: Prop: For interpolation math functions are treated as atomic algebraic terms. You interpolate a calc expression that is the sum of all the terms <dbaron> weighted sum, I hope :-) <dael> Rossen_: Okay. Any objections? <fremy> LGTM <dael> AmeliaBR: Yes, weighted sub by the interpolation factor <dael> s/sub.sum <dael> s/sub/sum <TabAtkins> Aka, if interpolating between any two expressions A and B, the interpolation is *defined as* calc(.X*A + (1-.X)*B) (plus any algebraic simplifications) <svoisen> jensimmons: There are links for both calendars at the bottom of this message https://lists.w3.org/Archives/Member/w3c-css-wg/2017OctDec/0076.html <dael> RESOLVED: For interpolation math functions are treated as atomic algebraic terms. You interpolate a calc expression that is the weighted sum of all the terms |
Thanks for bringing that to resolution so quickly! |
Thank you all so much for the quick resolution! |
For interpolation, https://drafts.csswg.org/css-values-4/#combining-values says:
While https://drafts.csswg.org/css-values-4/#calc-computed-value says:
So their computed values are not numbers, and there's no straightforward way to interpolate them. Should this be explicitly specified?
The text was updated successfully, but these errors were encountered: