As I was developing a cool new HTML5 (in the marketing sense) RIA tablet app, I noticed that it was acting a little slow. All the CSS transforms that were supposed to be hardware accelerated were stuttering slightly on the iPad 1, and quite a lot on Android devices. At first I just chalked it all up to the iPad 2:s beefier CPU, and the notoriously bad transformation performance on Android devices.
That is until I found this piece of code. Buried inside a reset.css file was this declaration:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Quite an eyeful, isn’t it? The highlight here is our tiny little tranlateZ() transform. I guess the original author intended to enable hardware acceleration on the page. So what’s the problem with this selector? Why is it causing this huge hit on performance? It’s elementary, dear Watson! The answer you seek is the C in CSS: it stands for cascading. Allow me to demonstrate with this piece of CSS.
1 2 3 4 5
Yes, it’s just an example. No, I don’t think descendant selectors are cool. But we’ll use this HTML as an example.
1 2 3 4 5 6 7 8 9
As you’ll likely see (with a sufficiently modern browser), our div is upside down. Since the selector applies to all elements, the rotations cascade down the DOM, being applied one at a time at each descendant separately. In a similar manner the CSS star selector applies to every single element in your DOM individually. Now, usually the translate3d() would be applied rather quickly, without any consequences, but with a dense enough DOM tree, it all starts to add up - and the app slows down to a crawl.
I removed the rule, committed, and performance was back up. Everything was nice and smooth on iPhone, Android and all the usual friends. In retrospect, I’m actually surprised the performance wasn’t even worse!