w3c / csswg-drafts

CSS Working Group Editor Drafts
https://drafts.csswg.org/
Other
4.47k stars 659 forks source link

[css-easing] Should we include the infinity for output progress value? #8344

Closed BorisChiou closed 1 month ago

BorisChiou commented 1 year ago

The definition of output progress value in [css-easing] includes the infinity:

The output progress value is a real number in the range [-∞, ∞].

However, there are some mismatched places in other specs:

  1. the definition of iteration progress of ComputedEffectTiming in [web-animations-1] uses double instead of unrestricted double. That means the progress doesn't include infinity or NaN.
  2. the interpolation section in [css-values-4] says the range of progress from easing functions doesn't include infinity.

Do I misread something? Or should we update the definition of output progress value and let it exclude infinity in [css-easing]? Or do we have to update other specs to match [css-easing]?

IMO, I prefer letting [css-easing] restrict the range of output progress value from easing functions because it makes more sense to me, i.e. use (-∞, ∞), instead of [-∞, ∞].

cc @birtles

BorisChiou commented 1 year ago

Note: I notice this when working on https://bugzilla.mozilla.org/show_bug.cgi?id=1807966.

tabatkins commented 1 year ago

I don't believe it's actually possible to produce an infinite value from any predefined easing function anyway, so yeah, adjusting the range to be exclusive at both ends sounds good.

birtles commented 1 year ago

Yeah, we recognized that there are currently no cases where the output can be +/- Infinity and changed the progress accordingly here: https://github.com/w3c/web-animations/commit/df138ee1314da46c6d671d7e406433c3e675ee61

emilio commented 1 year ago

@birtles @tabatkins but that's not quite right is it? Output can be infinite / nan if you use nan etc in a linear timing function...

emilio commented 1 year ago

Example from the above Gecko bug: transition-timing-function: linear(calc(15 / 0), 10 10%);

birtles commented 1 year ago

@birtles @tabatkins but that's not quite right is it? Output can be infinite / nan if you use nan etc in a linear timing function...

Yes, you're right. The spec edit I pointed to was from before the linear() timing function was introduced so I guess it made sense then.

Since linear() only exists in level 2 of CSS easing I guess level 1 could still exclude infinite values but Web Animations should be updated to be able to represent infinite / nan values.

jakearchibald commented 1 year ago

We could make infinite values result in an invalid linear()?

Loirooriol commented 1 year ago

animation-iteration-count: calc(1 / 0) is not infinite, it gets just clamped to a large finite number. Why should this be different?

emilio commented 1 year ago

hmm, shouldn't that per spec be actual infinity (or let's say, calc(infinity) or so?). In Gecko we don't actually yet ship the division by zero / infinity / nan keywords in calc() and IIRC that was one of the remaining bugs.

I guess https://drafts.csswg.org/css-values-4/#calc-computed-value doesn't quite specify what's the actual computed value of a <number> that happens to be calc(infinity), but it's weird that it would just be FLOAT_MAX effectively.

Loirooriol commented 1 year ago

https://drafts.csswg.org/css-values-4/#calc-range

Clamping is performed on computed values to the extent possible, and also on used values

By definition, ±∞ are outside the allowed range for any property, and will clamp to the minimum/maximum value allowed. Even properties that can explicitly represent infinity as a keyword value, such as animation-iteration-count, will end up clamping ±∞

birtles commented 1 year ago

Getting back to Boris' question about the progress member, if the easing function produces NaN, I wonder if it's better to handle that in Web Animations such that it falls back to the identity function (and have progress report that). That would be an easy edit and would cover CSS animations and transitions too.

For infinite values perhaps we could let progress report Infinity and rely on clamping at the point where we calculate the computed value.

(I'm away from my computer now though so I haven't checked the Gecko bug to see if that works there.)

tabatkins commented 1 year ago

We could make infinite values result in an invalid linear()?

Can't do "invalid", since it's not always detectable at parse time.

But yeah, as Oriol said calculations don't actually resolve to infinite values; they're clamped to something large (but undefined) by definition. So no, a linear() can't actually resolve to an infinite value.

(A given context could define that infinite values are allowed and so something specific with them, but none do currently, and we probably shouldn't without a great reason. In particular, doing anything different from "very large but finite" is probably a bad idea, and if you are consistent with "very large but finite", just relying on the implicit clamping is probably sufficient anyway.)

I guess drafts.csswg.org/css-values-4/#calc-computed-value doesn't quite specify what's the actual computed value of a <number> that happens to be calc(infinity), but it's weird that it would just be FLOAT_MAX effectively.

Yeah, the lack of a specified max is intentional; the actual value doesn't actually matter (any similarly-enormous number will do effectively the same thing in whatever context it appears in), and actually setting values would require a lot of extra research and specification effort. Just wasn't worth the cost for whatever minimal benefit consistency would bring us.

birtles commented 1 year ago

So no, a linear() can't actually resolve to an infinite value.

linear() is evaluated as part of https://drafts.csswg.org/web-animations-1/#calculating-the-transformed-progress and https://drafts.csswg.org/web-animations-1/#the-effect-value-of-a-keyframe-animation-effect where it can resolve to an infinite or NaN value.

We should probably handle at least NaN values there. For infinite values we could clamp there or we try to clamp them as part of the interpolating step or even later still. The latter will require ensuring infinite progress values are correctly handled by other parts of the system prior to interpolating (e.g. making progress an unrestricted double).

tabatkins commented 1 month ago

You still can't get a NaN. If you try and write either into the syntax, like linear(0, calc(infinity) 100%), it'll clamp to a UA-specified large value once the infinity escapes the calc(); similar with NaN (censored into an infinity, then clamped).

And you can't get a NaN in the output, either - none of the functions allows that to happen. Both linear() and cubic-bezier() have matching discontinuous behavior if the extrapolation line would actually be vertical, instead treating the first/last point as giving a constant output value.

You can potentially get an infinity, if you use a sufficiently sloped function and a sufficiently large/small input outside of the 0-1 range, but that should ideally be clamped as well, since it's an artifact of translating it to a JS double. So that should occur at the WebAnimations side, I think. I can put a note in Easing about it, tho.

tabatkins commented 1 month ago

Closing as invalid; CSS already theoretically allows infinities, and implicitly does UA-defined clamping (defined in Values 4). For any non-CSS usage of easing functions, they'll need to define what happens with values that are large enough to be treated as infinity - they can clamp, or use infinity natively, as they wish.

NaNs are censored so they don't escape a calc(), and none of the easing functions can directly produce a NaN on their won.