Loading mobile friendly images
My collegue, Andy Beer, and I have been working on a mobile optimised version of a website. CSS media queries provide an excellent way of rendering an appropriate layout for the screen size, however there is one issue that they don't solve and that's images.
You may have a website that has nice big banner images which look awesome on a monitor at 960px wide, but on a mobile version of the same website those banner images are too big in terms of both width and download size. What we wanted to do was use the same HTML markup for all devices, but only load the appropriate imagery for the screen size.
There are a number of solutions to this problem, all of them have pros and cons, so let's dive right in!
CSS background images
One of the neat things about CSS media queries is that if you reference an image in your CSS with a media query block, the device will only download that image if the screen resolution is correct. Here's a quick example:
/* mystyles.css */
@media only screen and (max-width: 480px) {
#header { background-image:url('myheader-480px.png'); }
}
@media only screen and (min-width: 481px) and (max-width: 800px) {
#header { background-image:url('myheader-800px.png'); }
}
@media only screen and (min-width: 801px) {
#header { background-image:url('myheader-960px.png'); }
}
This is great as you're saving on bandwidth and page rendering is faster. The downside is that you have to reference all your images in the CSS, which is not really practical.
Loading with Javascript
Another solution is to use Javascript and HTML5's data-* feature.
<!DOCTYPE html>
<meta charset=utf-8>
<title>Some page</title>
<script type=text/javascript src=//ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js></script>
<script type=text/javascript>
jQuery(function($){
// get the document width
var documentWidth = $(document).width();
// blank means use the image from the src attribute
var screenType = '';
if (documentWidth > 800) {
// big screen
screenType = 'big';
}
else if (documentWidth > 480) {
// medium device, for example a tablet
screenType = 'tablet';
}
if ( screenType != '' ) {
// find all images with the data-src-xyz attribute
$('img[data-src-' + screenType + ']').each(function(){
$this = $(this);
// set the src attribute to the optimised version
$this.attr('src',$this.attr('data-src-' + screenType));
});
}
});
</script>
<!-- Note: use the mobile optimised image as the default -->
<img src="logo-mobile.png"
data-src-tablet="logo-tablet.png"
data-src-big="logo-big.png">
OK, if you can get past the fact that I haven't closed my tags and there's no head or body tags (as HTML5 doesn't need them), then you'll see that I have an inline image with alt, src, data-src-mobile and data-src-tablet attributes (I thought I'd be nice and add the quotes!). At the top of the page is some simple jQuery to detect the screen size and load the appropriate image.
There are a couple of important things to note in this example. Firstly, the javascript can't be run until the DOM has loaded (as it needs to know if there are any img tags on the page), and more importantly, that I'm referencing the mobile friendly version in the src attribute and the bigger screen versions of the image in the data-src-mobile and data-src-mobile attributes. Why? Well, the browser will try to load the image that it finds in the src attribute, so this means that on the larger screens both the logo-mobile.png and the logo-big.png will be downloaded (try it in firebug if you want proof). As the mobile version is less likely to have bandwidth or a fast connection, that is the one I reference in the src attribute as it will only download the logo-mobile.png version as the jQuery code will not load the logo-big.png version as the screen size is too small.
So what happens if you don't have specific versions for each screen size?
The following line basically means that only images that have an attribute that matches the screen size will be replaced. So if you haven't got a nice high quality version, then the mobile version (specified in the src attribute) will be shown instead.
$('img[data-src-' + screenType + ']').each(function(){
Loading with Javascript variation
The Javascript version works well on mobile devices (or small screens), but the desktop user with the nice monitor ends up downloading two versions of the images, even though they will only see the big version. This isn't ideal and if they have Javascript disabled then they'll only see the small/low quality versions. There isn't (as far as I know) a perfect solution to this, but there is an imperfect solution!
<!DOCTYPE html>
<meta charset=utf-8>
<title>Some page</title>
<script type=text/javascript src=//ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js></script>
<script type=text/javascript>
jQuery(function($){
// get the document width
var documentWidth = $(document).width();
// default to mobile
var screenType = 'mobile';
if (documentWidth > 800) {
// big screen
screenType = 'big';
}
else if (documentWidth > 480) {
// medium device, for example a tablet
screenType = 'tablet';
}
// find all images with the data-src-xyz attribute
$('img[data-src-' + screenType + ']').each(function(){
$this = $(this);
// set the src attribute to the optimised version
$this.attr('src',$this.attr('data-src-' + screenType));
});
});
</script>
<img src="about:blank"
data-src-mobile="logo-mobile.png"
data-src-tablet="logo-tablet.png"
data-src-big="logo-big.png">
All I've done here is changed the src attribute to "about:blank" and added a data-src-mobile which references the mobile friendly version of the image. By doing this only one version of the image will be downloaded, the downside is of course that you'll need to have Javascript enabled.
Possible Improvements
You could modify the jQuery to execute when the page is resized, you may also want to hide images using CSS (and enable with Javascript) so that users without Javascript won't see placeholders. Both of these don't really have many real-world situations where they would be a requirement, and hiding images may have issues if you have rich content that isn't allows visible.
So there you go, I'm by no means a mobile optimisation expert, but this is what I've found through trial and error.
- Posted in:
- jQuery


Comment by Julian Halliwell – May 25, 2011
Comment by John Whish – May 26, 2011
There must be a better solution which covers all bases...
Comment by Julian Halliwell – May 26, 2011
Comment by jeff – July 29, 2011