Back

HERE BE DRAGONS: Some of the experiments on this page might cause your device to crash!!! Although all of the code on this page is quite innocent, I have noticed some freezing of devices! (Usually only after many, many, many tests though)

CSS experimentations, Mobile Performance

While testing an app I'm building in HTML5, and most notably CSS3, I ran into some performance issues. Mostly these dealt with perceived performance. Perceived performance is about tricking the user into feeling like the application is snappy. I was doing this with a simple loader screen, but this screen took over a second to appear :(.

The first thing I did was having a look at the javascript portion of the application. My suspicions lying in the direction of my pub-sub system, thinking that the system was too serial and some slow code (possibly an ajax-call) was delaying the appearance of the loading screen. Luckily the playbook allows remote-debugging and I was able to profile the software. Unfortunately, it looked like the javascript code was quite snappy, the webkit renderer however appeared not to be...

Now I have read plenty about optimizing CSS, especially concerning complex rules and such, but more noticeably redraw issues. My new suspect was laid to bare and I started testing away. Since my app has no images, relying (so far) entirally on CSS3 trickery, there were plenty of suspects on the horizon. It soon appeared that I had a compounded set of hard to render properties adding up to my slugish UI. I would like to rehash those experiments in small 'boxed' versions, hopefully being able to expose several key issues that may cause slow rendering.

Be aware that all of these issues cause no noticeable lag on a personal computer, these are mainly issues that will be noticeable on less powerful devices, think tablets/mobiles/etc...

Adding/Removing pseudo elements

I mark a state-change on the body of the page and based on that cause the loading effects to appear. In my case I'm adding a pseudo element when the loader is required, and remove it again when it's done. This is easy, but understandably bad for performance...

.test1 #test1::before { content: "Test1"; position: absolute; background: red; }

Click here to toggle the first experiment.

Fluid size

The size of the loader-screen was defined only in min-width and min-height. Although this allows it to scale, it also adds uncertainty that needs to be resolved, stacked on top of the previous method, not good...

.test2 #test2::before { content: "Test2"; position: absolute; background: red; min-width: 50%; min-height: 50%; z-index: 50; }

Click here to toggle the second experiment.

Gradient Background (with alpha-transparency)

The icing on this cake was without a doubt the effect of webkit needing to calculate a gradient alpha-transparent background. Sure it looks cool, but even in a relatively clean and simple test-case I really noticed the delay (after fixing the afore-mentioned issues).

.test3 #test3::before { content: "Test3"; position: absolute; background: red; min-width: 50%; min-height: 50%; background: rgba( 255, 0, 0, 0.5 ) -webkit-gradient(radial, 50% 50%, 30, 50% 50%, 800, from(rgba(0,0,0,0)), to(rgba(0,0,0,0.75)), color-stop(90%, rgba(0,0,0,0.75))); z-index: 50; }

Click here to toggle the third experiment.

Showing/Hiding pseudo elements

I started resolving afore-mentioned issues one by one. The first thing to improve is to create the pseudo-element by default, but hiding it. In my app this works extremely well, but it may not always be the case. The best performance is gained by using opacity or vissibility to hide the element, but this may cause overlay problem (an invisible overlay blocking the UI...), for my app this was not the case though.

#test4::before { content: "Test4"; position: absolute; background: red; min-width: 50%; min-height: 50%; background: rgba( 255, 0, 0, 0.5 ) -webkit-gradient(radial, 50% 50%, 30, 50% 50%, 800, from(rgba(0,0,0,0)), to(rgba(0,0,0,0.75)), color-stop(90%, rgba(0,0,0,0.75))); z-index: 50; visibility: hidden; } .test4 #test4::before { visibility: visible; }

Click here to toggle the fourth experiment.

Position Fixed / Top-Right-Bottom-Left

With the advent of CSS3 and HTML5 Microsoft got of it's lazy ass and finally implemented proper support for both position: fixed and position from all 4 directions. The first allowing us to (finally) position an element relative to the viewport. All the other major vendors allowed us to do this years ago as defined by CSS2.1, Microsoft introduced this more recently. From that same spec comes the definition of top, right, bottom and left. These 4 properties can be used together to create an element that resizes along with it's positioned element! That's some awesome power in layouts... Again, Microsoft was late to the party, what a surprise.

#test5::before { content: "Test5"; position: fixed; top: 1em; right: 1em; bottom: 1em; left: 1em; background: rgba( 255, 0, 0, 0.5 ) -webkit-gradient(radial, 50% 50%, 30, 50% 50%, 800, from(rgba(0,0,0,0)), to(rgba(0,0,0,0.75)), color-stop(90%, rgba(0,0,0,0.75))); z-index: 50; visibility: hidden; } .test5 #test5::before { visibility: visible; }

Click here to toggle the fifth experiment.

No more Gradient :(

No smart solution to get around the gradients though. Although I could try a media-query, the gradient isn't particularly important to me at this time, the perceived performance takes precedence.

#test6::before { content: "Test6"; position: fixed; top: 1em; right: 1em; bottom: 1em; left: 1em; background: rgba( 255, 0, 0, 0.5 ); z-index: 50; visibility: hidden; } .test6 #test6::before { visibility: visible; }

Click here to toggle the sixth experiment.

Size matters

While writing up this article and testing the hell out of it I noticed something that I had not noticed (or actually not tested) before. Size actually really matters a lot as well in these examples. The final example, although being optimised as much as I can, loads almost at the same speed as the third test. While the next-to-last test is noticeably slower. The main difference between the two being size!! I did do some quick test to confirm this and found it to be true. I didn't feel like extensively documenting this, so I hope that those truly interrested in the subject at hand, got all the way to the end of this document :)

Conclusion

Even though mobile devices are getting immensely powerful, especially compared to old computers, you cannot assume that all CSS3 and HTML5 prowess will perform well on them. Perhaps it isn't always about raw power, hopefully some of these issues can be resolved by better software implementations... Until that time, be aware that complex CSS can cause sluggish UI's just as much as JavaScript can. Yes, this makes targeting the mobile platform complex compared to personal computers, but comparatively speaking it's still peanuts when thinking back about the browser-wars between Microsoft and Netscape.