Altering image sizes responsively in all browsers

If you view the responsive web page page by Ethan Marcott in IE8, you’ll notice that it doesn’t work in the same way as modern browsers. This is because IE8 and below doesn’t support media queries – the smart bit of css we use to conditionally style our page based on current or device width. We also need to evaluate media queries to set our img tag through javascript using windows.matchMedia and media query list addListener– this isn’t supported in IE9 or less.

We need another polyfill – to add media queries to IE8 and below and to add media query matching and listening in IE9 (as well as any other unsupported platforms). The responsive polyfill I’ve written combines elements of Scott Jehl’s respond.js polyfill for media queries, Paul Irish’s matchMedia.js polyfill and my own code for media query listeners whilst keeping performance a priority.

This allows us to use code to detect when to change the image or image size in the browser and set the correct image path on initial page load. We thus take the following steps:

– set up a media query to detect changes at a width of 600 pixels
– read the contents of noscript tags and add an image to the dom depending on the media query
– listen to the media query so that when it changes we can modify the image path accordingly.

var mql = window.matchMedia('only screen and (max-width: 600px)');
var elements;
	
//Get contents of noscript tags 
var tags = document.getElementsByTagName("noscript");

//Add image to dom depending on media query
for (var i=0, len=tags.length; i<len; i++) {
  var markup = tags[i].textContent.trim();

  if (mql.matches) markup = markup.replace("/large/", "/small/");
  tags[i].insertAdjacentHTML('afterend', markup);
}

//Scale up to large / down to small when media query changes
mql.addListener(function() {

  if (!elements) elements = document.getElementsByTagName("img");
		
  var from = (mql.matches) ? "/large/" : "/small/";
  var to = (mql.matches) ? "/small/" : "/large/";

  for (var i=0, len=elements.length; i<len; i++) {
    if (elements[i].className.indexOf("responsive") > -1)
      elements[i].src = elements[i].src.replace(from, to);
  }
});

View the example

Thoughts on this technique

It should be pointed out that strictly speaking, once we have the large image we dont need the small image - it is better just to scale it down. However I also think that the smaller image in a responsive design may often be different - perhaps a more cropped version - anyway this page exists to demonstrate the basic technique only.

We also dont use a jQuery style document.ready type approach - this is simply not needed for such a simple example - placing the code in the footer is more than sufficient. However - because the images are loaded fairly late in the day you can see the image 'waterfall' as they are loaded. A more advanced technique may only display them once they are fully loaded, perhaps with css such as

img.responsive {display:none}
noscript img.responsive {display:block}

Is it worth the extra script vs the reduced download? Probably. Certainly the noscript code is small. Making IE9 and below fully responsive may not be worth it however.

PS. The responsive script doesn't currently read style tags in the parent document - it could easily be modified to do so however.

Altering image sizes responsively in all browsers

Leave a Reply

Your email address will not be published. Required fields are marked *