Open Bug 1787544 Opened 3 years ago Updated 3 years ago

FLIP animation technique does not work

Categories

(Core :: CSS Transitions and Animations, defect, P3)

Firefox 106
defect

Tracking

()

People

(Reporter: sime.vidas, Unassigned)

Details

Attachments

(3 files)

Attached file flip-test.html

User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:106.0) Gecko/20100101 Firefox/106.0

Steps to reproduce:

  1. Open the attached HTML document
  2. Click the red heading

Actual results:

The heading instantly moved down by 100px.

Expected results:

The heading should have animated.

Further information:

I have copy-pasted the JavaScript code from the article ”FLIP your animations” 1. My test page works in Chrome and Safari. In Firefox, the heading animates only once every ~10 tries (reload the page to try again). Also, I’m confused about the code. Normally, a double rAF is required to run code after the next frame, but the code on the test page uses a single rAF, and yet it works in Chrome and Safari.

Someone on Twitter pointed out that it might be the classList.add() call that makes it work in Chrome and Safari.

requestAnimationFrame(function () {
  el.classList.add('animate-on-transforms');
  el.style.transform = '';
});

I looked at the performance recording in Chrome (see attached screenshot), and there are multiple style recalculations within the next frame, which is also twice as long as usual.

The Bugbug bot thinks this bug should belong to the 'Core::DOM: Core & HTML' component, and is moving the bug to that component. Please correct in case you think the bot is wrong.

Component: Untriaged → DOM: Core & HTML
Product: Firefox → Core

After experimenting with this locally, the problem seems to be with how quickly the transition property takes effect. That is, how soon after setting the transition property changes to other properties get animated.

Status: UNCONFIRMED → NEW
Component: DOM: Core & HTML → CSS Transitions and Animations
Ever confirmed: true

As best I can tell, Chrome and Safari seem to be buggy here.

There should be no style flush between running

el.style.transform = `translateY(${invert}px)`;

and

el.classList.add('animate-on-transforms');

and

el.style.transform = '';

hence there is nothing to transition.

The first line of code runs in a click event handler (after updating style/layout for the current frame) and the next two lines run in a rAF callback (i.e. before updating style/layout for the next frame) so when the style update does happen, the before-change style should be the same as the after-change style.

I think it comes down to how each engine interprets the "before-change style". I can't link to the spec right now because it's down again, but it has:

...define the before-change style as the computed values of all properties on the element as of the previous style change event...

unfortunately:

...this specification does not define when a style change event occurs

but typically browsers have been fairly consistent about this.

I think it's worth filing this on Chrome/Safari to let their engineers chime in on why this is happening. If there's a good reason for it, it might be reasonable to update Firefox, but so far, as best as I can tell, the Chrome/Safari behavior seems wrong to me. (And if we do update Firefox, it would be good to know why Chrome/Safari behave the way they do so we can make sure it's specced.)

Just a quick note to all: The CSS WG drafts are now hosted on GitHub as well.

Relevant spec text: https://w3c.github.io/csswg-drafts/css-transitions-1/#starting

Yeah, updating layout before rAF seems wrong, for what is worth.

Attached file flip-with-logging.html

I had a little dig into what Chrome is doing and it's a bit of a mystery to me. Things I've observed:

  • The frame time for the onclick callback and the rAF callback are sometimes the same (they shouldn't be)
  • The frame time reported by document.timeline.currentTime and the timestamp passed to requestAnimationFrame sometimes differ (they shouldn't)

Unfortunately each test run produces different results so I guess even if there were WPT for this, they would show up as intermittents.

Perhaps the best thing to do here is to write some WPT, then flag Blink folk for review and see what they have to say about it.

(In reply to Brian Birtles (:birtles) from comment #8)

I had a little dig into what Chrome is doing and it's a bit of a mystery to me. Things I've observed:

  • The frame time for the onclick callback and the rAF callback are sometimes the same (they shouldn't be)

I think we probably can't write a WPT for this particular case since it's possible that due to vsync browsers re-use the same instant. I wouldn't expect that to happen at quite the frequency that I'm observing it in Chrome, but it's still probably acceptable from a spec point of view.

I believe the second case, however, should never happen.

The severity field is not set for this bug.
:emilio, could you have a look please?

For more information, please visit auto_nag documentation.

Flags: needinfo?(emilio)
Severity: -- → S3
Flags: needinfo?(emilio)
Priority: -- → P3
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: