Yesterday I went to the Bristol Skill Swap on responsive design, and one of the questions at the end of the panel was about performance optimisation for mobile devices.
Sure the panel were all about minifying your assets, using Gzip, serving icon fonts and so on.
But I wanted to show here a technique that we’re using on an e-commerce website we’ve built.
It’s not a bulletproof technique, but it can (from our tests) cut the page load time by half on certain pages.
Lets see how we’ve done this.
Where to start
Let say that for this example we’re using Twitter bootstrap as our responsive framework. Twitter bootstrap has ‘responsive design’ ready classes.
.visible-phone
.visible-tablet
.visible-desktop
.hidden-phone
.hidden-tablet
.hidden-desktop
In your html code, adding a .visible-desktop class to an element will make it ‘visible’ on large monitor sizes but hidden on tablet and mobile.
The visible is the trick here, because unfortunately the content still has to be loaded and transferred over the network. This can mean precious time load depending on the state of your connection, especially on an e-commerce website where less speed = less sales.
But a good 1/2 of an e-commerce website is marketing content. Banners, images, sliders trying to attract clicks from the user.
Most of this marketing content will be hidden on the mobile view, offering the customer on the move a much leaner experience.
It was just a shame to have to download all those elements that were going to be hidden anyway on mobile.
Solutions?
Unfortunately there are no bulletproof solutions here. Some will go the route of a m.website.com subdomain. I’m not fond of that solution because it makes sharing / managing views a big pain.
Instead we decided to go for user agent sniffing. I know it’s not particularly great, but it’s the most pragmatic solution we found to the problem.
The idea is to have the responsive layout working first with your layout classes. So way to have this piece of html (well HAML):
.hidden-phone.hidden-tablet
Big marketing content
#product
%h2 Product name
%p product description
It’s easy enough to understand that the page will be loaded and the css will hide the marketing content.
What we want is not loading it here. So we started with this Railscasts and just tweaked the user agent section.
before_filter :prepare_for_mobile
private
def mobile_device?
if session[:mobile_param]
session[:mobile_param] == "1"
else
request.user_agent =~ /'palm|blackberry|nokia|phone|midp|mobi|symbian|chtml|ericsson|minimo|'audiovox|motorola|samsung|telit|upg1|windows ce|ucweb|astel|plucker|'x320|x240|j2me|sgh|portable|sprint|docomo|kddi|softbank|android|mmp|'pdxgw|netfront|xiino|vodafone|portalmmm|sagem|mot-|sie-|ipod|up\\.b|'webos|amoi|novarra|cdm|alcatel|pocket|ipad|iphone|mobileexplorer|mobile'/
end
end
helper_method :mobile_device?
def prepare_for_mobile
session[:mobile_param] = params[:mobile] if params[:mobile]
end
Just remove the request.mobile line and update the user_agent Regexp.
Now we have a mobile user agent sniffing that might cover 80% of our need, we just need to plug it to the view for a quick win:
- unless mobile_device?
.hidden-phone.hidden-tablet
Big marketing content
#product
%h2 Product name
%p product description
Adding this on all the .hidden* condition will gives you a nice performance boost.
Brownies point, caching?
The problem with this method is that server side caching needs to take the mobile_device? into account.
I would suggest to add “mobile-#{mobile_device?}” at the end of your caching/fragment key.
It’s not perfect!
As I said, it’s not perfect, waiting for the browsers to offer us a better solution, but it’s the most simple and pragmatic solution we found.
What do you think? And did you have to do things like this before?
Edit: My friend Andrew Nesbitt made some valid point on twitter, you can read them in this thread. So let me be clear again, I know this technique has flaws, but I haven’t found anything better yet. Use it if you know what you’re doing.