Web animation gotchas - HTTP 203

Chrome for Developers · Beginner ·🌐 Frontend Engineering ·5y ago

Key Takeaways

The video discusses common issues and workarounds for web animation using CSS transitions

Full Transcript

okay audio synchronization time three two one three two one brilliant it's not a little bit like like a power rangers like audio synchronization time oh the worst power rangers ever the power to synchronize audio [Music] so i've been doing animation on the web for probably about 20 years now um i used to write a library for it that the bbc used uh back when i worked there uh and i'd say more recently mostly animation work i do is like when i do slides for talks is kind of one of the times i really throw lots of weird animation effects and stuff to kind of to try and keep people awake while i'm drawing on about something boring and standardly um but i i don't normally give my credentials up front like that but the reason i'm doing that now is because i still get caught out by loads of animation stuff on the web i think it's really hard and i think some of the tools we have at our disposal are not so great um and could be a lot better yeah this this this rings very much to them for me true to home um i think i just miss english either way but yeah i remember when we were writing procs that i had to write like an animation library for the canvas-based animations and you were like i've done this before let me tell you of all the struggles you're gonna encounter yes exactly um so let's talk about two relatively basic animations fading something in you just saw that there and fading something out there you go but even those have a ton of complexity and gotchas um yeah i i only feel like i'm starting to come to some conclusions of how these basic animations should be done in a way that's safe and avoids all of the gotchas i would say way back when i would use um jquery or green sock or the library i wrote um i used green sock because i used to be a flash developer i don't know if i've mentioned that enough times but uh that's that green stock was a an animation library for flash that then moved to the web so i kind of i used that for a bit but then we got these things css transitions so the older animation libraries were just changing inline styles over time either by using set timeout or later request animation frame which would be the proper way of doing it but with this you've got compositing and the animation happening off the main thread so like your opacity and transforms even if your main thread is janky these animations will run nice and smooth pretty good for things like hover effects because no javascript needed there you go you can you know throw out your jquery and your green sock or whatever and that's what i did enough i'm just going to use these this is it from now on but i was also using javascript for interactions so i wanted to drive transitions with javascript so the user clicks a button now i want the new thing to fade in so i'm going to create it give it an opacity of zero add it to the document and then transition it to full opacity cool yeah yeah cool yeah no go on tell me about it we i the only reason i know this is because we actually had a question about this i think on the first big web quiz at some point yeah and then we started testing and discovered that browsers were still having behaving differently here actually so i think because you know this is all javascript there is no yielding to the browser between the append and the subsequent changes of the style so the browser the the rendering engine only sees that the transition and an opacity of one because the previous change is invisible to the rendering engine spot on yes absolutely the browser never sees the opacity zero never thinks about it in terms of styling uh it's just a javascript value and it's overridden before it thinks about styling anything so the way you work around this is either by waiting until the next frame which means using requestanimationframe twice of course it's twice because requestanimationframe is before the next frame so if you want to push into the next frame you have to use it twice or you hack around it so all i'm doing here is using get computer style and just calling get computer style is not enough you have to then read a property from it and that is when the browser will think about the style and it thinks about that opacity zero and then it will transition to one fine okay let's fade something out there we go pretty good good start um but what if like opposite to before i want to remove it once it's faded out so let's give that a go you get an event so there we go job done can you see the gotcha here uh actually i cannot and not even die for a long time uh until it caught me out and it's that events bubble so i could get this event not for when my transition finishes but from when some other thing finishes its transition and once you start getting into more complex transitions where like something inside fades out slightly sooner you start finding your things disappearing from the document much sooner because you're actually catching that event from another animation so so you should check for yes yeah so that caught me out as well but if that element was already zero opacity you get no transition so you don't get an event which is great so now if you're building a sort of more generic animation system that's something you have to check because people will say like try you know make this go to zero and then remove it and if it's already zero they just want it to be removed um this kind of code is extremely fragile because you're checking you know you'll be checking what the input value versus uh the computed value but even with opacity zero percent and zero are the same thing the computed value will always come out as zero but the user of the library might have given you zero percent um you're not going to get a transition from those two because they compute to the same value and we don't have the tools to easily convert arbitrary values into compute values also if it's displaying on or it's inside an element that's displaying on or it's not in the document you're not going to get a transition event so this this is just not going to work properly so we'll throw all of that out and start again what i'm going to do this time is use css animations because this arrives slightly later um than transitions but you know we've had them for at least a decade now i i'd say this just works so i'm you know setting the opacity and then it's animating from opacity 0 to its computed style which is going to be one and i don't have to do any computed style hacks this will just work which is great yeah this is my current go go-to preference for making things appear when added can get when they get added to the dom just like it automatically plays just place once it stops at the end it's brilliant which is great isn't it because you we're now in a situation where it's easier to use css animations for transitions than css transitions great excellent but yes i agree with you this is moving towards how i do things with animations these days so what about the fade out and remove that's a you know slightly different model uh so i'm gonna add another keyframe animation this time fading out and off we go all right we still need to deal with the bubbling still have the event bubbling issue but this time it's fine if the value is the same so if you're animating from opacity 0 to opacity 0 you will still get the event which is great oh really yes i did not know that you won't get it if it's displayed on or inside an element that's displaying on so you know we're making steps forward but we're not there yet but then enter the web animations api this just works which is great so i'm saying like providing my one and only keyframe which is opacity zero uh and i give it an offset zero which means that this keyframe is at the start of the animation the offset is between zero and one and off it will animate it'll animate from opacity 0 to whatever the style resolves at which would be one by default but it could be something else so this works in those cases as well does this currently work in chrome this exact syntax yes it does yeah so what you're thinking there is like and for a long time you had to specify at least two key frames um yeah you don't anymore this just works it will figure out the other one automatically which is great i wish it was there from the start it wasn't but yeah this works now and and it's well supported right the web animation api is if you're targeting modern browsers it's everywhere like it arrived to safari more recently than the others but it's there now so this is how i do animations now well it shows that chrome supported web animations ati from 44 to 84 but i think that wasn't complete support right so that that table seems to be a tiny bit misleading that's true um so in terms of the multiple keyframe thing i think it was actually firefox that landed that first so credit to them but yeah chrome supports it now so yes although that chart shows everything looking good for a long time in chrome there are features that i'm showing today that arrived in between then and i didn't look up when so don't ask me but it's been in they've been in chrome for multiple versions now so they're safe to use so what about fading out um there you go that's it uh javascript animations stay finish even if it's display non or if it's not in the document so you don't have to overcome that as well actually there is a bug here in chrome of course there is yeah bloody chrome spoiling all that fun the promise resolves too late so the the animation will finish and then sometime later the promise resolves which if you're doing accurate animation work this is far too late so instead of the promise use the events this is fixed in canary so um it's on its way to stable but you know that's a workaround that works today i want to talk about more gotchas what if i wanted to fade something from whatever it is now to not point to opacity and leave it i'm not going to remove it from the document something like this can you see the gotcha um i mean i'm i'm immediately drawn to just one keyframe where i don't know if it's implicit that's at the end of the animation if you just specify one keyframe that's a good point uh yes it is like but if you provide one keyframe it implies the end keyframe for some reason okay so they got you here and i don't see it yeah and i mean if you ran this code you would see it immediately because here's what it does the animation ends and then the animation is gone so everything that the animation was affecting stops being affected so yeah that's why i usually i almost always define the fill behavior because i just don't trust the defaults there we go job done fill forwards and yeah now it works so just to be clear that means when the animation ends you know the timeline you have keyframes and you play from one key to the next phil tells you what happens when the time is outside these two keyframes should you loop should you fill or there's probably others as well but yeah that's what this property does looping is different it's it's forwards and backwards and both are the values so yes if you have an animation that is delayed um a fill of backwards means it will apply the first keyframe while it's waiting for the animation to start a fill of forwards means that once the animation is done it will hold the last state both does both but i have come to the conclusion that this is a huge gotcha and every time i have done this it has bitten me at some point later on especially if i'm doing something a little bit more complicated and it's because of this it doesn't work like the animation has higher priority oh because the animation is technically still running i guess effectively it's still held and while an animation is running or in while it's still happening to some extent it has priority over almost everything um the only thing it doesn't have priority over is um important styles you know when you do exclamation important it doesn't have priority over that but yes if your solution is to use important styles you've done something wrong earlier on right so we need to fix this some way and actually like there's a method which i'm going to struggle to remember like document.getanimations you will see all of these animations that have filled forwards so anything that ever ran essentially is going to be in there oh that i didn't know that one that's neat yes uh because like in css you will remove that animation by removing the um the style resolution which has the the animation property on it so if you remove that class name then it removes the animation with web animations you need to deliberately cancel the animation if you wanted that um so what's the answer and it's taking me years to figure out and so i might still be wrong um but here's what i've here's the conclusion that i've come to so strapping just don't animate ever don't animate it's awful people hate it no i'm going to make an animate 2 function which takes the elements and then the the animation arguments the keyframes and the options i'm going to create the animation and return it so this will run to completion and then snap back to the start values as we saw before so we're going to fix that i'm going to create finish events i could use the promise except for chrome that bug so i'm going to use the events and then i'm going to call commit styles this is an api that not many folks seem to know about what it does is it commits inline styles for the animation at its current position so you can call this multiple times in the animation and it will just like dump out inline styles for whatever's happening right now there's a problem here though because the current position is finished so everything has already snapped back to the start so this doesn't work there is a spec disagreement on this already that like maybe that shouldn't be the behavior maybe this should just work if you call it after it's finished it will give you the final styles but that's not the way browsers behave so i'm going to add phil both and i know i said that was bad and it is but we need it so we have those styles when the animation ends and then once committed cancel the animation which removes it from the queue and you end up with the inline styles so you've got that that it's held the final position but it means that you can update inline styles later on and it will all work and for the people already wondering i'm pretty sure this event listener doesn't leak no because it fires once and then it the browser knows it's not going to be fired again especially once the animation is garbage collected so the animation can't be restarted because animation can get garbage collected yeah yeah i guess the listener could leak if you if you're holding onto the animation object because you could restart the animation and in which case you could get finish again but yeah it's otherwise fine it's not something to worry about my previous solution to this was to um apply the inline styles manually uh on the on the and i wouldn't use fill uh at all because i hate it but this this raises a question about composited animations that i've seen browser folk argue about so if you've got an animation that completes you get your finish event and then you set the inline styles what if your main thread is blocked at that point and the animation is happening on the compositor some people would argue that the animation would complete snap back to the original values and then sometime later you get your event so you would still have a visual flicker like animation completes it snaps back and then you apply the inline styles i couldn't get any browser to actually do this so it seems like it's a it's a bug they've solved or worked around in some way but that is not in the spec at all so hmm maybe that will change in future i mean it would make sense to to to set to somehow tie the value that the animation object is representing to the time that the event is being processed or the event is created and put in the event queue but yeah that definitely something that needs to be specified and written down that that is how it's supposed to behave and even if the values are synchronized it it's more about what you're seeing on the screen that you need that's using crowds and what it seems like browsers do is they run the animation on the compositor so off the main thread but then the removal of the animation where it would snap back to the start point that is still handled on the main thread so that means that you get your events in synchronization with that thing happening but there's no spec for how the compositor works but browsers seem to be doing the right thing but to defend against changes in terms of how the compositor works with the main thread this code will defend against that because it it's going to use that fill forwards or fill both in this case to hold that final frame until your javascript gets to run and it's your javascript which removes the animation from the queue there you go like 20 years it's taken me to get to this combination of my own learning and also features being and you know what you had to use phil in the end after all after all but there is discussions in the spec to avoid having to do this where if you call commit styles at the end in the finish events it will apply the final styles which that's just what i want that's what i always wanted just make that easy for me please but in the meantime i at least now have a simple small function that does exactly what i want and that's all i've got i having fiddled with writing an animation engine which makes it sound way more fancy way fancier than it was in prox um i appreciate this the simplicity of what you boiled it down to so i'll put it in a gist i might want to copy it i'll yes i'll link to it in the description along with the various bugs and spec bits and arguments and stuff that are happening and i'll put that uh yeah down in the description [Music] it's loaded did you clap that second time yeah it's just perfectly insane my earphones maybe the sound well maybe the gbc swallowed it yeah probably i could see that happening

Original Description

Fading something in, and fading something out – sounds simple right? Unfortunately not! Jake & Surma talk through the various gotchas of animating the web, and how to work around them. Using CSS transitions → https://goo.gle/2TXTUCB Using CSS animations → https://goo.gle/3et8gEq The web animation API → https://goo.gle/3mXbV0C getAnimations → https://goo.gle/3oXMLk4 commitStyles → https://goo.gle/38d6PsN Event listeners and garbage collection → https://goo.gle/32c4TNd Spec discussions → https://goo.gle/3k1zbIE The final animateTo function → https://goo.gle/363WVHn JavaScript animation libraries: jQuery → https://goo.gle/34XEowU Greensock → https://greensock.com/ AnimeJS → https://animejs.com/ The old library Jake made (don't use it) → https://goo.gle/34ZFGaU Other videos in the series → https://goo.gle/2wneQLl Subscribe to Google Chrome Developers here → https://goo.gle/ChromeDevs Also, if you enjoyed this, you might like the HTTP203 podcast! → https://goo.gle/2y0I5Uo
Watch on YouTube ↗ (saves to browser)
Sign in to unlock AI tutor explanation · ⚡30

Playlist

Uploads from Chrome for Developers · Chrome for Developers · 0 of 60

← Previous Next →
1 Polymer Performance Patterns (The Polymer Summit 2015)
Polymer Performance Patterns (The Polymer Summit 2015)
Chrome for Developers
2 Polymer Power Tools (The Polymer Summit 2015)
Polymer Power Tools (The Polymer Summit 2015)
Chrome for Developers
3 Chrome Dev Summit 2014 – Chrome Case Studies
Chrome Dev Summit 2014 – Chrome Case Studies
Chrome for Developers
4 Web Directions Code 2015 round up
Web Directions Code 2015 round up
Chrome for Developers
5 Maintainable Code - HTTP203
Maintainable Code - HTTP203
Chrome for Developers
6 iron-ajax… wat?! -- Polycasts #26
iron-ajax… wat?! -- Polycasts #26
Chrome for Developers
7 The Guardian - Supercharged
The Guardian - Supercharged
Chrome for Developers
8 ES2015 (next version of JavaScript), Totally Tooling Tips (S2 Ep1)
ES2015 (next version of JavaScript), Totally Tooling Tips (S2 Ep1)
Chrome for Developers
9 #AskPolymer: Rob answers all the questions ever -- Polycasts #27
#AskPolymer: Rob answers all the questions ever -- Polycasts #27
Chrome for Developers
10 The Future of JavaScript - HTTP203
The Future of JavaScript - HTTP203
Chrome for Developers
11 Data Binding 101 -- Polycasts #28
Data Binding 101 -- Polycasts #28
Chrome for Developers
12 The Guardian part 2 - Supercharged
The Guardian part 2 - Supercharged
Chrome for Developers
13 The Future of Web Audio: with Chris Wilson and Chris Lowis
The Future of Web Audio: with Chris Wilson and Chris Lowis
Chrome for Developers
14 Chrome 46: New motion-path animations, client hints and service worker improvements
Chrome 46: New motion-path animations, client hints and service worker improvements
Chrome for Developers
15 Sublime Snippets, Totally Tooling Tips (S2 Ep2)
Sublime Snippets, Totally Tooling Tips (S2 Ep2)
Chrome for Developers
16 #AskPolymer: How do you make the show? -- Polycasts #29
#AskPolymer: How do you make the show? -- Polycasts #29
Chrome for Developers
17 Critical Path CSS, Totally Tooling Tips (S2 Mini Tip #1)
Critical Path CSS, Totally Tooling Tips (S2 Mini Tip #1)
Chrome for Developers
18 Binding to Objects -- Polycasts #30
Binding to Objects -- Polycasts #30
Chrome for Developers
19 Player FM - Supercharged
Player FM - Supercharged
Chrome for Developers
20 Where’s the Designer? #AskPolymer -- Polycasts #31
Where’s the Designer? #AskPolymer -- Polycasts #31
Chrome for Developers
21 Jake Beats Wikipedia - HTTP203
Jake Beats Wikipedia - HTTP203
Chrome for Developers
22 Supercharged Observers! -- Polycasts #32
Supercharged Observers! -- Polycasts #32
Chrome for Developers
23 Jai's Web blog - Supercharged
Jai's Web blog - Supercharged
Chrome for Developers
24 Windows Command-line Tooling, Totally Tooling Tips (S2, Ep4)
Windows Command-line Tooling, Totally Tooling Tips (S2, Ep4)
Chrome for Developers
25 What about internationalization? #AskPolymer -- Polycasts #33
What about internationalization? #AskPolymer -- Polycasts #33
Chrome for Developers
26 Developing for Billions (Chrome Dev Summit 2015)
Developing for Billions (Chrome Dev Summit 2015)
Chrome for Developers
27 Google+ Performance Improvement Comparison
Google+ Performance Improvement Comparison
Chrome for Developers
28 Deploying HTTPS: The Green Lock and Beyond (Chrome Dev Summit 2015)
Deploying HTTPS: The Green Lock and Beyond (Chrome Dev Summit 2015)
Chrome for Developers
29 Progressive Web Apps (Chrome Dev Summit 2015)
Progressive Web Apps (Chrome Dev Summit 2015)
Chrome for Developers
30 Instant Loading with Service Workers (Chrome Dev Summit 2015)
Instant Loading with Service Workers (Chrome Dev Summit 2015)
Chrome for Developers
31 Increase Engagement with Web Push Notifications (Chrome Dev Summit 2015)
Increase Engagement with Web Push Notifications (Chrome Dev Summit 2015)
Chrome for Developers
32 Engaging with the Real World: Web Bluetooth and Physical Web (Chrome Dev Summit 2015)
Engaging with the Real World: Web Bluetooth and Physical Web (Chrome Dev Summit 2015)
Chrome for Developers
33 Asking for Permission: respectful, opinionated UI (Chrome Dev Summit 2015)
Asking for Permission: respectful, opinionated UI (Chrome Dev Summit 2015)
Chrome for Developers
34 Polymer - State of the Union (Chrome Dev Summit 2015)
Polymer - State of the Union (Chrome Dev Summit 2015)
Chrome for Developers
35 Building Progressive Web Apps with Polymer (Chrome Dev Summit 2015)
Building Progressive Web Apps with Polymer (Chrome Dev Summit 2015)
Chrome for Developers
36 Introduction to RAIL (Chrome Dev Summit 2015)
Introduction to RAIL (Chrome Dev Summit 2015)
Chrome for Developers
37 DevTools in 2015: Authoring to the max (Chrome Dev Summit 2015)
DevTools in 2015: Authoring to the max (Chrome Dev Summit 2015)
Chrome for Developers
38 RAIL in the real world (Chrome Dev Summit 2015)
RAIL in the real world (Chrome Dev Summit 2015)
Chrome for Developers
39 #ChromeDevSummit talks are up - W00T! -- Polycast #34
#ChromeDevSummit talks are up - W00T! -- Polycast #34
Chrome for Developers
40 V8 Performance from the Driver's Seat (Chrome Dev Summit 2015)
V8 Performance from the Driver's Seat (Chrome Dev Summit 2015)
Chrome for Developers
41 Quantify and improve real-world RAIL (Chrome Dev Summit 2015)
Quantify and improve real-world RAIL (Chrome Dev Summit 2015)
Chrome for Developers
42 Owning your performance: RAIL (Chrome Dev Summit 2015)
Owning your performance: RAIL (Chrome Dev Summit 2015)
Chrome for Developers
43 HTTP/2 101 (Chrome Dev Summit 2015)
HTTP/2 101 (Chrome Dev Summit 2015)
Chrome for Developers
44 Leadership Panel (Chrome Dev Summit 2015)
Leadership Panel (Chrome Dev Summit 2015)
Chrome for Developers
45 Build Processes, Totally Tooling Tips (S2, Ep 5)
Build Processes, Totally Tooling Tips (S2, Ep 5)
Chrome for Developers
46 Accessibility (Chrome Dev Summit 2015)
Accessibility (Chrome Dev Summit 2015)
Chrome for Developers
47 Binding to Arrays -- Polycasts #35
Binding to Arrays -- Polycasts #35
Chrome for Developers
48 HTTP2 - HTTP203
HTTP2 - HTTP203
Chrome for Developers
49 Chrome 47: Splash Screens, requestIdleCallback and better desktop notifications (New in Chrome)
Chrome 47: Splash Screens, requestIdleCallback and better desktop notifications (New in Chrome)
Chrome for Developers
50 Call For Submissions - Supercharged
Call For Submissions - Supercharged
Chrome for Developers
51 Cross Device Testing, Totally Tooling Tips (S2 Ep6)
Cross Device Testing, Totally Tooling Tips (S2 Ep6)
Chrome for Developers
52 Testing AJAX with Web Component Tester -- Polycasts #37
Testing AJAX with Web Component Tester -- Polycasts #37
Chrome for Developers
53 Slack: Extended Xmas Special - Supercharged
Slack: Extended Xmas Special - Supercharged
Chrome for Developers
54 Browser testing with Travis & Sauce Labs -- Polycasts #38
Browser testing with Travis & Sauce Labs -- Polycasts #38
Chrome for Developers
55 Optimize for production with Vulcanize -- Polycasts #39
Optimize for production with Vulcanize -- Polycasts #39
Chrome for Developers
56 Highlights from Chrome Dev Summit 2015
Highlights from Chrome Dev Summit 2015
Chrome for Developers
57 Chrome 48: Custom buttons in notifications, DevTools Security panel, and Presentation mode
Chrome 48: Custom buttons in notifications, DevTools Security panel, and Presentation mode
Chrome for Developers
58 Crisper: Protecting your Polymer app with CSP -- Polycasts #40
Crisper: Protecting your Polymer app with CSP -- Polycasts #40
Chrome for Developers
59 How do I use Sass with Polymer? #AskPolymer -- Polycasts #41
How do I use Sass with Polymer? #AskPolymer -- Polycasts #41
Chrome for Developers
60 Colors – DevTools Tonight #0 (Pilot)
Colors – DevTools Tonight #0 (Pilot)
Chrome for Developers

Related Reads

Up next
How to Skyrocket Your Performance on Twitter Using Video
Spiel Creative
Watch →