Fix: CSS Animation slow or choppy in mobile browsers

I’m developing an iPhone app using the PhoneGap library, which lets you write your app as if it were a website. That means any UI transitions or animations have to be written the way you would for any modern website targeting Webkit: CSS3 transitions (mobile javascript is too slow for frame by frame calculations).

Unfortunately, CSS transitions can be a little slow, a little choppy, even on iPhone 4 and the faster Android based phones. The problem is that, by default, webkit doesn’t involve the GPU unless you’re doing 3D transforms. With desktop horsepower, thats fine. On a mobile device, that GPU could really help.

So how do you force webkit to share the processing load with the GPU?

Apply this style to the element you’re animating:

-webkit-transform: translateZ(0);

Simple, but effective.

26 thoughts on “Fix: CSS Animation slow or choppy in mobile browsers”

  1. whoah that blog site will be superb i love looking at you. Maintain the excellent artwork! You feel, lots of people are searching for this info, you can help him or her enormously.

  2. Hi, I am using 2D transforms. The webkit animation is slow in android when compare to ipad/iphone. Is it helpful to mention this fix to solve my issue?

    1. I never tested it on android, but since they’re using the same rendering engine, I assume the same fix would work. Only one way to find out…

      1. This only helps in browsers that support hardware rendering. There’s only a handfull of Android phones that support hardware rendering right now – so unfortunately there is a small chance this would help with animation on android.

        The general idea is that when you’re updating css transformations on objects you use translate3d instead of translate; as in translate3d(10px,10px,0);

        The big problem with this is older android os’s don’t support the translate3d transform…

  3. I’ve been working on a mobile webapp with some drag/slide animation features, and have changed many of my translateX transform animations to translate3d(#,0,0), as touch responsiveness under the former was choppy at best, and practically absent at worst. I can confirm that this fix works for Webkit-based browsers on iOS and Android (I’m testing on a Samsung Galaxy Nexus as well as several generation’s of the iPhone), but would advise that developers use it sparingly, as an abundance of hardware-accelerated effects on the page can really eat through a viewer’s battery, and hardware accelerated elements seem to render more slowly when the part of the page containing them is loaded/reloaded. Also, apparently the opacity property also triggers hardware rendering in many cases, so if you’re frequently manipulating the transform property via JavaScript, defining an opacity value of 1 may serve as a welcome alternative to a superfluous translate3d property included only to trigger the hardware rendering.

    1. An abundance of animations would not affect the users battery. You’re either using the gpu or you’re not. If you have one dom element with z-rendering enabled, then you’re using the users battery.

  4. This is probably one of the simplest and groundbreaking things I have seen in a while. jQuery animations also have the ability to SUCK on the mobile platforms, but this little trick works wonders. With my small app I appled this to the body of the page and all elements that are animated now run smooth.

  5. You are a genius.
    This solves 50% of my problem and 0% was answered in Apple forums (the regular one. It seems I have to be a paid user, not just “registered” in order to browse the dev forums)

    If you find the solution to the other 50% of the reasons why websites become really irresponsive I look forward for a new post! That is, the elements being transformed require the whole page outer bounds to be re-calculated to FIT the damn viewport with every frame/change.

    I tried every combination of the viewport tag attributes, no success. It only sets the initial view, and the page still gets re-drawn with every frame.
    I tried using widths for everything, and images, no success.
    Getting rid of shadows helped a little the speed, but didn’t stop the resizing.

    So the website is un-browse-able.

    Hope you find a solution

    Thanks.

  6. So i can use that fix and continue to use any js library like jquery, zepto, jqtouch etc.,? Or should i use plain css for page transforms and other animations?

    1. You can use any javascript library you want, but the animations themselves must be written in CSS, not javascript. It is absolutely vital for mobile developers to learn CSS animation instead of javascript.

      The reason is that Javascript is actually very inefficient for animation, and it’s only recently, with the proliferation of mobile browsers, that we are starting to notice this.

      You see, with a JS animation (e.g. created using jQuery’s animate function), the javascript library sets an interval timer (lets say, 33ms, which is about 30 frames per second), and on that interval, it figures out where the animated element should be, using complex math calculated by the CPU, and then puts it there. Unfortunately, if the CPU is too slow to do that calculation every interval, it gets backed up and the animation stutters. jQuery and other JS animation tools do some work to combat this, sensing a drop in frame rate and trying to make the interval wider, to give it more time to complete the calculations, but it’s often too-little-too-late.

      On the other hand, when you do a CSS animation (e.g. using the transform or webkit-transform css properties), you leave it to the GPU to simply calculate where the element should be as often as it can. As soon as it calculates the element’s new position and places it there, the GPU starts the calculation again. This means the animation is always as smooth as the GPU can possibly make it, no matter what. If you animate too many elements for the GPU to handle it may still have trouble, but instead of ugly stuttering, it will be a more graceful drop in framerate.

      Hope that helps.

  7. Thanks you so much !!
    It works perfectly !!! i was really upset when i saw the lame animation in iphone/android.
    Now it works perfect :)

  8. Thanks for this post, it was an APP SAVER!

    ADDITIONAL TIP: If you are animating an element with NESTED elements that are significantly styled, try adding “-webkit-transform: translateZ(0);” to the child element style definition(s) as well. Made a huge difference for me.

  9. Unfortunately, this makes transitions noticably choppier for my page (on an iPad 3), not smoother.

    > An abundance of animations would not affect the users battery. You’re either using the gpu or you’re not. If you have one dom element with z-rendering enabled, then you’re using the users battery.

    This is wrong. For one thing, the GPU is *always* being used by iOS, since it’s used for compositing. For another, of course you’re using more battery with lots of transitions, as you’re causing far more composition operations to occur. You’re using battery any time something is changing. There are more distinct visible frames, each of which has to be rendered (whether it happens on the CPU or GPU–in reality it’s both). It’s not like the GPU is something that gets turned on and left on while you’re using it (like the gyroscope or wifi); it wakes up for the work it needs to do and then idles again.

    However, the difference is probably not significant and certainly not worth worrying about.

  10. Chris, To say your little one-liner was a lifesaver would be a complete understatement. You literally saved me hours of optimisation. Thank you for this trick!

  11. Wow, my images rotates like a charm….. It did in firefox and chrome on android, but not in the normal android browser.

    Now it does!!!!

  12. Great tip! but I still have a question, as some said above, use Css transform accelarate the animations, but trying something like change margin and padding values, still sucks on my android.

    1. I think it’s probably because margin and padding make the browser re-float everything else on the page. If you can avoid animating those values, do it.

    1. I’m always weary of making a rule apply to everything. Seems like a recipe for trouble, though I don’t have an example to give you.

      Also, this advice can be deprecated now, since the modern mobile browsers have fixed this issue.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>