[csswg-drafts] Animation and opacity clamping (#3340)

ewilligers has just created a new issue for https://github.com/w3c/csswg-drafts:

== Animation and opacity clamping ==
The *-opacity animation in http://jsfiddle.net/ericwilligers/wzet0kdr/ reports different results in different browsers (result below).

The specifications for various opacity properties say

> Computed value: the specified value converted to a number, clamped to the range [0,1]

When does the clamping occur?

Is this text from https://www.w3.org/TR/css-color/#typedef-alpha-value correct and relevant?
> Values outside these ranges are not invalid, but are clamped to the ranges defined here at computed-value time. 

WPTs such as [fill-opacity-valid.svg](https://wpt.fyi/results/svg/painting/parsing/fill-opacity-valid.svg?label=stable&aligned) and [stroke-opacity-valid.svg](https://wpt.fyi/results/svg/painting/parsing/stroke-opacity-valid.svg?label=stable&aligned) and [opacity-valid.html](https://wpt.fyi/results/css/css-color/parsing/opacity-valid.html?label=stable&aligned) demonstrate that current browsers serialize specified values unclamped.

If an animation keyframe specifies 'inherit', and the parent's specified value for the property is outside the range [0,1], should the parent's specified value or the clamped value be used as the keyframe value?

If an animation keyframe specifies a value outside the range [0,1], should the specified or clamped value be used as the keyframe value?

```
#parent {
  opacity: -2;
}

#child {
  animation: anim; 
}

@keyframes anim {
  0% {
    opacity: inherit;
  }
  100% {
    opacity: 2;
  }
}
```

**Firefox**

 |  progress  |   0  |   0.125  |   0.25  |   0.375  |   0.5  |   0.625  |   0.75  |   0.875  |   1 | 
--: | :--: | :--: | :--: | :--: | :--: | :--: | :--: | :--: | :--
 |  fill-opacity  |   0  |   0.125  |   0.25  |   0.375  |   0.5  |   0.625  |   0.75  |   0.875  |   1 | 
 |  stroke-opacity  |   0  |   0.125  |   0.25  |   0.375  |   0.5  |   0.625  |   0.75  |   0.875  |   1 | 
 |  flood-opacity  |   0  |   0.125  |   0.25  |   0.375  |   0.5  |   0.625  |   0.75  |   0.875  |   1 | 
 |  stop-opacity  |   0  |   0.125  |   0.25  |   0.375  |   0.5  |   0.625  |   0.75  |   0.875  |   1 | 
 |  opacity  |   0  |   0.125  |   0.25  |   0.375  |   0.5  |   0.625  |   0.75  |   0.875  |   1 | 
 |  shape-image-threshold  |   0  |   0.125  |   0.25  |   0.375  |   0.5  |   0.625  |   0.75  |   0.875  |   1 | 
 |  stroke-dashoffset  |   -2  |   -1.5  |   -1  |   -0.5  |   0  |   0.5  |   1  |   1.5  |   2 | 

**Blink**

| progress| 0| 0.125| 0.25| 0.375| 0.5| 0.625| 0.75| 0.875| 1|
--: | :--: | :--: | :--: | :--: | :--: | :--: | :--: | :--: | :--
| fill-opacity| 0| 0| 0| 0| 0| 0.5| 1| 1| 1|
| stroke-opacity| 0| 0| 0| 0| 0| 0.5| 1| 1| 1|
| flood-opacity| 0| 0| 0| 0| 0| 0.5| 1| 1| 1|
| stop-opacity| 0| 0| 0| 0| 0| 0.5| 1| 1| 1|
| opacity| 0| 0.25| 0.5| 0.75| 1| 1| 1| 1| 1|
| shape-image-threshold| 0| 0.25| 0.5| 0.75| 1| 1| 1| 1| 1|
| stroke-dashoffset| -2px| -1.5px| -1px| -0.5px| 0px| 0.5px| 1px| 1.5px| 2px|

**Safari 12**

| progress| 0| 0.125| 0.25| 0.375| 0.5| 0.625| 0.75| 0.875| 1| 
--: | :--: | :--: | :--: | :--: | :--: | :--: | :--: | :--: | :--
| fill-opacity| -2| -1.5| -1| -0.5| 0| 0.5| 1| 1.5| 2| 
| stroke-opacity| -2| -1.5| -1| -0.5| 0| 0.5| 1| 1.5| 2| 
| flood-opacity| 1| 1.125| 1.25| 1.375| 1.5| 1.625| 1.75| 1.875| 2| 
| stop-opacity| 1| 1.125| 1.25| 1.375| 1.5| 1.625| 1.75| 1.875| 2| 
| opacity| 1| 1| 1| 1| 1| 1| 1| 1| 1| 
| shape-image-threshold| 0| 0.125| 0.25| 0.375| 0.5| 0.625| 0.75| 0.875| 1| 
| stroke-dashoffset| -2px| -1.5px| -1px| -0.5px| 0px| 0.5px| 1px| 1.5px| 2px| 

**Edge**

 |  progress  |   0  |   0.125  |   0.25  |   0.375  |   0.5  |   0.625  |   0.75  |   0.875  |   1 |   
--: | :--: | :--: | :--: | :--: | :--: | :--: | :--: | :--: | :--
 |  fill-opacity  |   0  |   0  |   0  |   0  |   0  |   0  |   0  |   0  |   0 |   
 |  stroke-opacity  |   0  |   0  |   0  |   0  |   0  |   0  |   0  |   0  |   0 |   
 |  flood-opacity  |   1  |   1  |   1  |   1  |   1  |   1  |   1  |   1  |   1 |   
 |  stop-opacity  |   1  |   1  |   1  |   1  |   1  |   1  |   1  |   1  |   1 |   
 |  opacity  |   1  |   1  |   1  |   1  |   1  |   1  |   1  |   1  |   1 |   
 |  shape-image-threshold  |   undefined  |   undefined  |   undefined  |   undefined  |   undefined  |   undefined  |   undefined  |   undefined  |   undefined |   
 |  stroke-dashoffset  |   -2px  |   -2px  |   -2px  |   -2px  |   -2px  |   -2px  |   -2px  |   -2px  |   -2px |   


(The stroke-dashoffset rows shows how the animation progresses when no clamping is involved.)


I suspect that Firefox clamps both keyframes to [0,1]. This explains the properties animating smoothly from 0 to 1 over the full animation duration.

Blink has a [bug](https://bugs.chromium.org/p/chromium/issues/detail?id=908058) where fill-opacity / stroke-opacity / flood-opacity / stop-opacity are not clamped to [0,1], except when updating the computed style with the result of an interpolation. Thus the interpolation result runs smoothly from -2 to 2, but the result is clamped to 0 when progress <= 0.5 and the result is clamped to 1 when progress >= 0.75.

Blink clamps the opacity / shape-image-threshold computed values to [0, 1]. Thus the inherited value for the initial keyframe is 0. The interpolation runs smoothly from 0 to 2, but the result is clamped to 1 when progress >= 0.5.

Is the Firefox animation behavior correct, or is the Blink animation behavior for opacity / shape-image-threshold correct?


Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/3340 using your GitHub account

Received on Saturday, 24 November 2018 08:35:26 UTC