When building responsive websites, you immediately run into the problem of trying to implement responsive images which would be sized correctly depending on the user's device. Either you want to hide images from mobile users or give them an optimised version. The problem centers on the page loading anything referenced in the HTML even if it’s hidden by CSS in your media queries. This can lead to your mobile users getting a big hit from content they aren’t even using.

This problem can’t be handled entirely on the server side. You have to make contact with the user’s device before you can determine how much screen width is available. Therefore the solution has to involve JavaScript. The feature detection has to intercept the server request before the entire DOM has loaded into place, otherwise the page could make a request for the wrong image. You also have to be able to serve an image to users who have JavaScript switched off, so a full JavaScript solution is not acceptable.

We came across a couple of existing libraries. You can read our blog post on implementing the Filament Group solution. We later found another solution, which suggests using PHP to serve your images. Browser support was an issue for us with the Filament Group solution so we started experimenting with our own ideas. We came up with the idea of adding an image into a <noscript> tag and then enhancing the site for JavaScript users by removing the <noscript> tag and creating a new image element with a dynamic source attribute.

Using the Webkit developer tools, HTTPWatch for Internet explorer and HTTPfox for Firefox we were surprised to discover that removing the element with JavaScript prevented the request being made to the server. After a quick Google we discovered that it works because children of the <noscript> tag are not added to the DOM. This appears to work in all the browsers we’ve tested, even IE6, with the single exception of Opera’s Dragonfly, which crashed repeatedly when we tried to test.

We created a Rails helper gem, responsive_image_tag, to insert the necessary markup into the page:

1
2
3
4
<span class="img-placeholder"></span>
<noscript data-mobilesrc="small.jpg" data-fullsrc="big.jpg" data-alttext="your alt text" class="responsivize">
   <img src="big.jpg">
</noscript>

The helper places the default image inside a <noscript> tag, which is then deleted by the JavaScript library. The image attributes such as full size, mobile size and alt text are also stored as HTML5 data attributes on the <noscript> tag so they are available in the DOM for the JavaScript to access.

The library relies on the premise that child elements of the <noscript> tag are not added to the DOM, so deleting the <noscript> prevents an HTTP request being made to the server. This way only the image being requested by the dynamically inserted image tag is making a request.

To insert the dynamically created image element into the page you need a parent element in the DOM to append to. The Rails helper also creates a <span> tag with a class of “img-placeholder” to house the new image.

When the DOM is ready the JavaScript object responsiveImageTag detects all <noscript> elements on the page with a class of “responsivize”.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var responsiveImageTag = {
    replaceInitialImages:function() {
        var platform = "desktop";
        var responsiveImages = $$(".responsivize");
        var i,
            noOfresponsiveImages = responsiveImages.length;
        //test for available width in current browser window
        if(screen.width <= 767){ //767px, anything smaller than an ipad is considered mobile
          platform = "mobile";
        }
        
       //set initial source element on image
       for(i = 0; i < noOfresponsiveImages; i = i + 1 ){
       var noScriptElem = $(responsiveImages[i]);


It retrieves the HTML5 data attributes ("data-mobilesrc", "data-fullsrc", and "data-alttext") and then creates an image tag with the correct source depending on the available screen width of the users device.

1
2
3
4
5
6
7
8
var img = window.document.createElement("img");
       img.alt = noScriptElem.attr("data-alttext");
       if(platform === "mobile"){
          img.src = noScriptElem.attr("data-mobilesrc");
       }else{
          img.src = noScriptElem.attr("data-fullsrc");
       }
       img.className = "responsive";

The responsive-image-tag javascript inserts the new element into the page and the <noscript> tags are then hidden from view.

1
2
3
4
5
noScriptElem.prev().append(img);          
       noScriptElem.hide();
     }
   }
};

You can check out our github repo. It’s not a perfect solution. It has the elegance of a wading hippo. It adds a lot of extra markup into your page for each image tag you want to make responsive and it’s causing a page reflow as your page is loading, which could potentially impact performance if over-used.

Ideally we need an addition to the HTML5 specification to allow some kind of device recognition or feature detection for device specific assets. I believe there are several aspects of developing for mobile or developing responsively that we don’t have real standard support for right now and as a development community we need to be championing the need for these and getting them written into the spec now.