Animation and opacity clamping
Nobody has claimed this yet.
- Dominant language
- Bikeshed
- Stars
- 4.9k
- Forks
- 816
- PR merge metrics
- PR metrics pending
Description
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 and stroke-opacity-valid.svg and opacity-valid.html 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 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?
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reading the CSS Color specification text on alpha-value clamping and compare the WPTs fill-opacity-valid.svg, stroke-opacity-valid.svg, and opacity-valid.html. Review the reported Firefox, Blink, Safari, and Edge animation results, then determine and document when clamping applies to inherited and out-of-range animation keyframes.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- css
- Domain
- documentation, web-dev
- Issue type
- Documentation
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100