RESOLVED CONFIGURATION CHANGED 228896
CSS animation timing is broken when animating from scaleX(0) to scale(1)
https://bugs.webkit.org/show_bug.cgi?id=228896
Summary CSS animation timing is broken when animating from scaleX(0) to scale(1)
evan.exe
Reported 2021-08-07 06:33:08 PDT
Created attachment 435129 [details] A screen capture showing Chrome working correctly and Safari working incorrectly Repro: 1. Visit https://esbuild.github.io/ on Chrome or Firefox 2. Notice how the progress bars move together 3. Visit https://esbuild.github.io/ on Safari 4. Notice how the progress bars move separately at different speeds The animation is a simple linear CSS animation from left to right, and is completely broken in Safari.
Attachments
A screen capture showing Chrome working correctly and Safari working incorrectly (2.36 MB, video/quicktime)
2021-08-07 06:33 PDT, evan.exe
no flags
HTML snapshot of the current state of https://esbuild.github.io/ (20.48 KB, text/html)
2021-08-07 06:45 PDT, evan.exe
no flags
Testcase (1.88 KB, text/html)
2021-08-09 20:43 PDT, Simon Fraser (smfr)
no flags
evan.exe
Comment 1 2021-08-07 06:35:29 PDT
Looks like this is also broken on the latest version of iOS (version 14.7.1).
evan.exe
Comment 2 2021-08-07 06:45:05 PDT
Created attachment 435130 [details] HTML snapshot of the current state of https://esbuild.github.io/
Simon Fraser (smfr)
Comment 3 2021-08-09 20:43:23 PDT
Created attachment 435240 [details] Testcase
Simon Fraser (smfr)
Comment 4 2021-08-09 20:44:08 PDT
The broken animation has mismatched transform functions: @keyframes scale-bar { 0% { transform: scaleX(0) } to { transform: scale(1) } } so it interpolates via matrix interpolation. This appears to use the wrong timing function.
Simon Fraser (smfr)
Comment 5 2021-08-09 20:51:54 PDT
scaleX(0) is not invertible so we fall back to software animation.
Simon Fraser (smfr)
Comment 6 2021-08-09 21:12:22 PDT
This is about interpolation via matrix decomposition. We decompose the scaleX(0) matrix to: (WebCore::TransformationMatrix::Decomposed2Type) $1 = (scaleX = 0, scaleY = 1, translateX = 0, translateY = 0, angle = 0, m11 = 0, m12 = 0, m21 = 0, m22 = 1) and the scale(1) matrix to: (WebCore::TransformationMatrix::Decomposed2Type) $2 = (scaleX = 1, scaleY = 1, translateX = 0, translateY = 0, angle = 0, m11 = 1, m12 = 0, m21 = 0, m22 = 1) then interpolate scaleX and m11. Recomposing the matrix then causes m11 to affect scaleX in matrix[0][0]
Radar WebKit Bug Importer
Comment 7 2021-08-12 10:08:57 PDT
evan.exe
Comment 8 2021-08-12 16:03:45 PDT
Thanks for determining the root cause. In that case I'm going to change https://esbuild.github.io/ to use a small but non-zero scale value to avoid a non-invertible matrix. This means the original repro steps will no longer work, but you will still be able to reproduce this with the attached test case.
Simon Fraser (smfr)
Comment 9 2021-08-12 17:05:55 PDT
A small scale would work. You could also use scale(x, y) or scaleX(x) in both keyframes.
evan.exe
Comment 10 2021-08-12 17:20:06 PDT
> A small scale would work. You could also use scale(x, y) or scaleX(x) in both keyframes. Yes, but the problem is that CSS minifiers convert "scaleX(1)" into "scale(1)" and "scale(0, 1)" into "scaleX(0)", which prevents using both "scale" or both "scaleX" in this case if you're using a CSS minifier. See this code for example: https://github.com/cssnano/cssnano/blob/04bd16e9de5e2d4409fef74034edb7534cd9e457/packages/postcss-reduce-transforms/src/index.js#L93-L123. I believe that this CSS minification transformation is valid since these I'd expect for these forms to generate the equivalent matrix (i.e. "scaleX(0) == scale(0, 1)" and "scaleX(1) == scale(1, 1)"). Please let me know if that's not a valid CSS minification transformation and I can file an issue with the relevant CSS minifiers.
Antoine Quint
Comment 11 2023-05-11 08:01:50 PDT
This is working fine in Safari 16.
Note You need to log in before you can comment on or make changes to this bug.