Jump to content
GreenSock

Search In
  • More options...
Find results that contain...
Find results in...

CSS animations performance: the untold story


| GreenSock
75146

Note: This page was created for GSAP version 2. We have since released GSAP 3 with many improvements. While it is backward compatible with most GSAP 2 features, some parts may need to be updated to work properly. Please see the GSAP 3 release notes for details.

There are some interesting (and surprising) performance implications of using CSS animations that aren't widely known. I stumbled across a few of them while running tests for a customer in the advertising industry who is pushing to have GSAP adopted as the standard, so I recorded a screencast explaining what I found. I figured it was worth sharing:

Summary

  • Timeline recordings in Chrome Dev Tools don't show the overhead involved with CSS animation of transforms, so people often misinterpret the [lack of] data. Recordings look "clean" with CSS and "dirty" with JS which leads to faulty conclusions about performance.
  • CSS animations of transforms used twice as much CPU compared to JS according to Chrome's task manager.
  • CSS animations caused the main thread to bog down more than using JavaScript animations. User interaction is typically handled on the main thread, making things feel sluggish to the user. It is especially costly if you animate transforms along with almost any other property at the same time.
  • Webkit browsers have synchronization problems.
  • JavaScript was faster than CSS animations on every device that I ran this test on – the only exception was animating transforms in Webkit browsers (and then there's that heavy cost on the main thread and sync problems).
  • In order to independently control the timing/easing of transform components (rotation, scale, skew, position) in CSS, you must create a DOM node for each which negatively impacts performance. With JavaScript, no such workarounds are necessary. (see note below)
  • I love Dev Tools - I'm not knocking it at all. These things are just tough to measure.
  • Do your own tests! Don't put too much faith in Dev Tools or my tests. Use your eyes because ultimately perception is what matters to end users. Smooth movement and responsive UI are both important.

Links

UPDATE: After recording the video, I did some more tests that showed that one of the biggest contributors to the slowdowns in the pure CSS version was the fact that multiple elements had to be nested in order to accomplish the independent transform component controls. In other words, staggering the start/end times (or easing) of rotation, scale, and position is practically impossible in pure CSS unless you nest things like that, but there's a relatively significant performance tradeoff. When nesting could be avoided, pure CSS animation of only transforms did appear smoother on webkit browsers under heavy pressure and it was basically indistinguishable from optimized JS animations under all other levels of pressure.

Edited by GreenSock

Get an all-access pass to premium plugins, offers, and more!

Join the Club



User Feedback

Recommended Comments

Hi Jack! I'm a fan of GSAP and recommend it for many cases, but unfortunately a few things indicated in this video are not accurate. Because there was so much detail in the video, I'm going to handle things one by one. Task Manager. You only got to show the Browser process and not the Tab's own renderer process (or the GPU). Your results make sense because the browser takes over handling much of the animation instead of locking up the main thread. When you consider the other processes the numbers between the two approaches are fairly equivalent. FPS counter. This is tricky because we're relying on a FPS counter implemented in JS that runs on the main thread, but what we care about is how often pixels are drawn to the screen. Since compositor frames are distinct from main-thread frames, rAF cannot measure the performance of any CSS animations. (The Frame Timing API will solve this). I would recommend using the FPS counter in the Rendering tab of DevTools. Timeline not showing costs for CSS animation. Yeah, that's a pretty good bug. Try in Canary, as things look good there. You'll see heavy Recalc Style operations on the main thread . Synchronization. This is a great demonstration of what happens when you have compositor and main thread animations running concurrently on the same element AND you consistently blow your frame budget on one of the the threads. That sort of thing doesn't happen too often in practice, but it's something we keep an eye out for. Animating elem.style.top. You and I both know that 1) animating the top property isn't a performant choice and 2) top positions cannot be sub-pixel, so they are always fit to an integer. That just leads to jaggier animations in comparison to a transform. In your demo, however, neither of these really are the determining factor, but it's more of an exacerbation of the issue described next… This is an unfair benchmark. (You noticed this after you finished the video, but.. there it is.) In the CSS variant, there are FIVE divs representing each red box. In your GSAP variant, just one. This difference has a huge effect on the numbers; DOM size blows out Recalc Style costs quickly. You don't necessarily need five divs per box for CSS, though I'll admit it's not entirely elegant to handle the animations independently with only a single element and single keyframe animation definition. Regardless, it's doable. I've (quickly) redone the CSS bits to use a single element and encourage you to look at the results: http://codepen.io/paulirish/full/9712e8fb6a451e0ee7393d01e7f59f53/ Now that both variants use just one element per box, the performance between the two is completely comparable. Try the translate+scale+rotate or translate+top. No significant difference between CSS & GSAP. ... Ultimately for this benchmark, CSS and GSAP perform basically the same. GSAP has advantages for authoring and manipulating different transform properties independently, and CSS's advantage is that it's a fraction of the bytes necessary. I still recommend GSAP for ultimate control and authoring experience; it can handle some really ambitious animation asks and it's easily best-in-class.
Link to comment
Share on other sites

What a thoughtful response, Paul! Thanks for all the clarifications. Let me offer a few as well: FPS counter The goal had nothing to do with accurately measuring how often pixels got repainted (I tried explaining that in the video, but probably did a poor job and I guess naming it "FPS" added to the confusion). The sole purpose of that fps ticker was to measure the main thread performance, since JS only runs there. I wanted to show that there can be a cost on the main thread even when CSS animations of only transforms are running (which are widely assumed to run on a different thread, thus we'd expect the main thread to perform better, not worse). If I could do the video over, I'd explain this better. Sorry about that. Animating elem.style.top Very true - thanks for bringing it up. Keep in mind that the goal was to show that animating anything other than transforms/opacity along with those can have sync problems. It could be backgroundColor, padding, whatever. "top" was just easiest to see in the tests, that's all. I agree though - in 98% of the cases, it's best/fastest to animate position using transforms (I have seen cases where top/left is much more performant, but that's a rabbit trail). This is an unfair benchmark You said it's doable to independently control the transform components (x/y/scale/rotation) on a single element with CSS animations (including varying the start/end times and easing) - I'm very curious to see this. Your example codepen doesn't do that. Instead, it does all of them at the same time. Can you provide one that separates them properly? This is super important, and it's actually what prompted me to do this whole test originally - a guy emailed me saying that CSS animations could do what GSAP does in terms of independent control, but it requires nesting and my point was that the nesting probably wasn't "free" - there's a performance cost. Notice that x/y animate for the whole 10 seconds, but rotation only occurs during a middle portion (for 6 seconds) and the scale changes toward the end (for 4 seconds). As far as I know, this is simply impossible with CSS animations (without nesting). Did I misunderstand? Thanks again for chiming in, Paul. I've got massive respect for you personally and the whole crew over there at Google. You guys are doing wonderful things for moving the web forward, especially on the performance front.
Link to comment
Share on other sites

FPS Counter ~= Main Thread performance. Gotcha. Yeah makes sense. We've been discussing having idle/cpu time available in the Frame Timing API for similar reasons. Benchmark composition I misspoke on independently controlling the transform components. I now understand that independent transform control was a requirement of these tests from the start, but that wasn't clear from your tests as they were very much focused on main thread utilization and FPS. But yes, the poor performance of the CSS animations are direct downstream effects of the element nesting. To me, the big summary is this: If you need independent transform control, JS is going to have a significant win as your element count will balloon with a CSS-only approach. If you don't need that, performance will be comparable (assuming ideal implementations of both).
Link to comment
Share on other sites

Looking at the results in the video and the short discussion in the comments it again looks like generally speaking there is no winner in the performance debate between JS- and CSS-animations. Except for the synchronization problem all demos shown seem to have very comparable lag (or lack of lag) with both technologies on the actual animation. And that's what the user will eventually see. Ultimately it still feels to me that performance is not that big of a factor in deciding between JS- and CSS-animations and we are (again) very much nitpicking about something without a big influence on the user-experience (not saying that performance is not important. But between JS and CSS it seems to be the same difference.). It's just the implementation that affects the performance significantly (As the 5 DOM-elements vs 1 DOM-element shows). In the sense of Paul Irish's summary the decision should rather be if I need to build a complex animation with physics, separate timelines etc. that will be way easier to get right in JS or if I want to build a "simple" animation where the easy to understand, declarative syntax of CSS will make me and my coworkers happy (At least until the web animations API gets ready for production and we have a whole new topic to get worked up over). Performance being a smaller factor determined case dependent and fixed if necessary.
Link to comment
Share on other sites

Yeah, I think that's pretty fair, Karsten. If you're only going to be doing very simple stuff and don't need much backward compatibility, CSS is great. Very easy to sprinkle in rollovers or basic state changes. The challenge is that sometimes you *think* you'll only need simple stuff at the outset of your project, and then things change and it can get awkward if you choose a technology that has such limitations. "Oh shoot...we need an elastic ease? We need to rotate that thing while it's moving, but offset the start times? Umm..." You could always switch later, and maybe just use JS for the parts where you need more advanced features and cross your fingers that there won't be overlaps or integration needed between the two at some point. If you build with CSS, it could be a problem. If you build with JS, it won't. It's like buying an 8GB iPhone (or whatever) instead of one with more memory. Perhaps today you only have 7GB worth of needs, but when you get more music and apps, you might kick yourself for limiting your options. Example: you build an sequenced animation but then later add a login overlay that should pause all the animation on the page (or gradually slow them to a halt) and then resume when the user closes the window. Hm. If it's all built in CSS, it could get VERY code-heavy or impossible whereas if it's built with GSAP, it's maybe 2 lines of code. Done. If you don't want/need that kind of flexibility, CSS may be a great fit. Your point is completely valid - in most real-world projects, the performance difference between GSAP and CSS animations probably won't be the deciding factor anymore. I think that's great news. A few more thoughts can be found in this article from a while back: http://greensock.com/transitions/
Link to comment
Share on other sites



Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×