As probably many developers have already experience this over the past weeks:
I had a phonegap application for iOS that contained some visually animated components (a coverflow or a carousel for example). But after updating to iOS6 this is all flickring now and it feels horrible because it’s just stumbling and faltering on the new version of the OS.
There are several reasons for this and I cannot say which were already there in iOS5, however here are the two main reasons and instructions on how to fix that:
1. Not all CSS Properties trigger hardware acceleration any more
Previously there were quite a few properties that triggered a hardware acceleration, for example:
- -webik-transform: translate3d(x,y,z);
- -webkit-transform: preserve-3d;
As Apple states in its Developer Changelog for iOS6: ‘WebKit no longer always creates hardware-accelerated layers for elements with the
-webkit-transform: preserve-3d option.[...]‘ There is a need for new CSS properties to trigger the acceleration, unfortunately I’m not aware of any official document by Apple listing those properties.
How to fix it:
Here are three properties that have been proven to work (at least in combination, I have not yet tested them solo, but they should):
As this is going to trigger hardware acceleration for the specified elements this might still not completely fix all the issues, therefore please continue reading Nr.2.
2. Overlapping with other Elements
Since I cannot downgrade to iOS5 I cannot say for sure if this “issue” already persisted, however it heavily persists with iOS6:
If you have an element(Element A) that is hardware accelerated and animated, it will/might cause performance and visual issues when overlapping with other elements(Element B) that are not hardware accelerated, as Element A will trigger Element B to be re-rendered with every change of Element A(at the end of a CSS-transition or when updating CSS properties through JS), which will cause:
- flickering of Element B, since it renders a lot slower
- heavy slowdown of the animation, since it needs more CPU time to render leaving less time for JS execution
One thing I noticed: If Element A OVERlaps another element it is not slowing down the animation as heavy as if Element A was UNDERlapping another element. Also it does not really matter if the parent-container of Element A has ‘overflow: hidden;’ or ‘overflow: visible;’ – it still slows doen the execution if the overlapping occures outside the bounds of the parent container.
How to fix it:
a) This can be simply fixed by giving ALL overlapping elements the CSS properties that trigger hardware accerleration. (see 1.)
(My first approach to fix this was by alternating the DOM-order to only have OVERlapping elements, however fix a) is way easier and works way better – for me.)
3. Avoid changes between ‘display: none;’ and ‘display: something;’
Changing the display-state on iOS is like adding or removing an element to and from the DOM and is therefor a very heady calculation depending on how many items you have in your DOM that can easyly cause the UI to freeze for a second or more.
How to fix it:
Instead of using the display-property, use the tranform-property instead, if you want to hide an item you can use something like this: transform:
and if you want to show the element, just set the values to 0:
You have to set the ‘position: absolute;’ though. This method needs a little bit more work than using ‘display’, however the performance of your webapp will thank you greatly for that.
I hope this helps someone as I was struggeling with this issue for quite a while, thoughts or additions on this article are very welcome!