> Weird webkit box-shadow bug

Today I finally received my new iPad and to my surprise some CSS intensive applications seemed to run smoother on an iPad 1 than on the new shiny Apple tablet.

Specifically I tested hexaga.me –my open source HTML5 puzzle game– on the third generation iPad and in some occasions the CSS animations resulted extremely laggy.

I’ve done a quick video to show you how bad the new iPad is compared to an iPad 1. It is not obvious at first sight, but look at the tiles as soon as I tap the blue button (when the tiles drop back into the original position).

On the new iPad (on the left) the tiles jump from the top to the bottom row with no animation at all, while on the old iPad you get a pretty smooth transition.

I reduced the elements on screen trying to isolate the culprit of this weird behavior and I narrowed it down to a couple of reasons.

First of all the new iPad seems more susceptible to DOM changes (in my case innerHTML and appendChild). But removing all the DOM changes didn’t help me reach the same smoothness of the iPad 2 (and not even of the iPad 1).

As soon as I removed box-shadow from all the elements on screen the game got back its velvet smooth transitions. You should already know that opacity, box-shadow, overflow:hidden + border-radius and few others impact on the overall performance, but this seems especially true on the retina display.

So –now more than ever– avoid box-shadow.

But this is not the end of the story.

Have a look at this demo ( http://cubiq.org/dropbox/bs ) on your iPad. On the top left there are a dozen divs with box-shadow applied. At first you’ll see a choppy animation. As soon as you tap on the “Fix it!” button the tiles run smoother.

All that the fix does is to add a top:0 to the divs. They are already set to position:absolute but if you don’t give them a top or a bottom property they interfere with the main animation. The FPS count goes from 36 without the fix to 58 with the fix applied on my iPad 3.

/Share the joy

/Reactions

  • Box shadow is usually implemented by some sort of per-pixel effect, like a box blur. I’m guessing that the retina display tries to render a 10px blur as a 20px underneath, which means 4x the pixels and 4x the math. And that’s the best case for a box blur. Something like a gaussian blur will be exponentially worse. Ouch!

    On the other hand, I thought this would be accelerated by a shader and cached in a texture, so it should only matter once per load. Strange.

  • Did you try -webkit-transform: translate3d(0,0,0); to trigger GPU acceleration?

    • It makes no difference

        • Author: Joe Critchley
        • Posted on: 2012/03/29
        • At: 23:04

        Just checking that you definitely applied this to the element that is animating?

      • Joe: absolutely

    • Author: Matt Dana
    • Posted on: 2012/03/29
    • At: 21:30

    I’m sorry, I’m really just posting a comment so that I get to click on your fantastic Post Comment button.

    • Author: JokeyRhyme
    • Posted on: 2012/03/29
    • At: 22:21

    CSS is definitely worse in iOS 5 than it was in 4. In fact, I think my team may have stumbled on an infinite-loop bug that is specific to iOS 5+ on the iPad (the iPhone is fine).

    Just saying that makes me feel crazy, how exactly does a declarative language cause an infinite-loop?!?

    Sometimes I feel as though having low expectations for Android is better than having high expectations for iOS. :P

      • Author: Mael
      • Posted on: 2012/03/30
      • At: 11:20

      Have you got a testcase ?

      • I used hexagame to make tests (which is open source). Next commit will have the fix applied so you can diff

  • Your aniframe test demo also runs more smoothly on my version of Chrome 18 beta (Windows 7 64-bit) after the Fix it button is pressed.

      • Author: Ward
      • Posted on: 2012/08/20
      • At: 04:53

      Interesting – New retina 15 inch macbook, Chrome Version 21.0.1180.79 – choppy anim, improved with the fix it button. Frame rates are identical to the post – mid 30′s before fix, high of 58 after fix. Animation seems to suffer from a cyclical pause as well, about every second or so, that goes away with the fix as well.

  • We’ve discovered much the same with our own testing — Anything that requires alpha-blends being done by the browser (hw-accelerated or not) is an issue for Retina displays. (Could also be large gradients that use rgba, etc.)

    Important to note that minor differences in distance/blur/spread can have a big impact here. Highly recommend checking out kangax’s research on the topic: http://perfectionkills.com/profiling-css-for-fun-and-profit-optimization-notes/

    • yes, it’s very frustrating. Sometimes changing few elements styling fixes the lagginess making it really hard to debug. As a general rule I try to avoid anything that involves alpha-blending (box-shadow included).

    • Author: Denham
    • Posted on: 2012/03/30
    • At: 05:41

    I ran your test on an iPad 2 (iOS 5.1) and it also had the ‘jerky’ animation, fixed when using the button. Maybe not specific to the iPad3?

    • yes, that is not specifically an iPad3 bug. I found it while trying to fix the iPad 3 bug and I thought it was worth mentioning it.

  • good to know about the top:0 trick!

  • Great stuff to know, Matteo.

    Your post spurned me to find some sort of documentation or tool on css property performance, and have found this tool by Andy Edinborough:

    http://andy.edinborough.org/CSS-Stress-Testing-and-Performance-Profiling

    Looks like it could save a ton of time!

    • Author: Jonny
    • Posted on: 2012/07/16
    • At: 19:01

    Amazing! The framerate went from 14 to 58 on my iPhone 4.

      • Author: Andrew
      • Posted on: 2012/09/14
      • At: 03:51

      Same with me!
      On my iPod touch 4, the hexagons would move-stop-move-stop-move-stop at 14-ish fps and it shoots up to 58 when I click fix it.