W3C home > Mailing lists > Public > public-css-archive@w3.org > July 2019

Re: [csswg-drafts] [css-values-4] How to interpolate min/max/clamp? (#4082)

From: Amelia Bellamy-Royds via GitHub <sysbot+gh@w3.org>
Date: Tue, 09 Jul 2019 18:29:24 +0000
To: public-css-archive@w3.org
Message-ID: <issue_comment.created-509754885-1562696963-sysbot+gh@w3.org>
We already have rules for upgrading simple expressions to more complex ones in the [procedure for interpolating percentages and dimensions](https://drafts.csswg.org/css-values-4/#combine-mixed), 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: `10px` → `100%` is treated as `calc(10px + 0%)` → `calc(0px + 100%)`, and then the two quantities inside that calculation are interpolated separately.

Yes, for interpolating more complex `calc` expressions, the initial setup (expanding out the two values so they have parallel structure) gets more complicated. But that setup only happens once at the start of the transition. For each animation frame, you're only updating individual numbers & then calculating out the result.

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:

- `min(0px, 100%)` → `min(0%, 100px)`; interpolating term by term, the midpoint would be `min(0, calc(50px + 50%))` aka 0
- `min(0px, 100%)` → `min(100px, 0%)`; interpolating term by term, the midpoint would be `min(50px, 50%)` aka probably more than 0

Similarly, you can't simplify additions of different comparator functions on a term-by-term basis:

- `max(100px, 100%) + max(20%, 50px)` is neither equal to `max(150px, 120%)` nor to
  `max(100px + 20%, 50px + 100%)`; the first expression has three different `calc` expansions, depending on the relationship between % and px.

**_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 `min(50px, 100%)` → `min(100px, 50%)`, the expanded expression would be

- `calc(1*min(50px, 100%) + 0*min(100px, 50%))` → `calc(0*min(50px, 100%) + 1*min(100px, 50%))`;
  the midpoint would be  `calc(0.5*min(50px, 100%) + 0.5*min(100px, 50%))`

More generally, you replace each unique function with a variable. Transitioning between two non-identical functions results in an expression of the form `1a + 0b` → `0a + 1b`, with the interpolated value a progress point t defined as `calc( (1-t)*a + t*b)`.

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:

- `pow(2,3)` → `pow(2,4)` is the same transition as 8 → 16; the midpoint for a linear interpolation is 12, which is the same as `calc(0.5*pow(2,3) + 0.5*pow(2,4))`

- `max(10px, 16px)` → `max(30px, 24px)` (e.g., after subbing in px for em at computed time) is the same transition as 16px → 30px.

GitHub Notification of comment by AmeliaBR
Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/4082#issuecomment-509754885 using your GitHub account
Received on Tuesday, 9 July 2019 18:29:25 UTC

This archive was generated by hypermail 2.4.0 : Tuesday, 5 July 2022 06:41:50 UTC