Last Updated: September 09, 2019
·
1.135K
· okor

Responsive design image efficiency stats

This short and dirty script that will display a table of results for all images and background images (ignores 0/1px tracking pixels). It compares the elements display dimensions to the image src size.

Responsive design is cool, but it's important to make sure you're not sending more bytes over the wire than is necessary (especially with responsive design + elements that use background-size: cover). At Vox Media, we use image lazy loading combined with smart javascript to deliver the best image src size for a given element.

The script currently doesn't take scale/DPI into account, so if your testing for mobile devices you can either make a pull request (https://gist.github.com/okor/41e86dc2019075865d6a and I'll update this tip) or more easily just emulate the device in Chrome and adjust the scale / DPI multiplier to 1, rather than the normal 2 for say an iPhone 5.

So this:

Picture

Should be set to this:

Picture

// Requires jQuery and Underscore or LoDash

$ = jQuery;

function stripURLWrap(cssBackground){
  return cssBackground.replace(/^url/g,'').replace(/\(|\)/g, '')
}

function getPercentage(number) {
  return Math.floor((Math.round( number * 10 ) / 10) * 100) + '%';
}

var imageStats = [];

_.each( $('*'), function(node){
  var $node = $(node);
  var hasImage = $node.attr("src") || $node.css('backgroundImage');

  if (!hasImage) return;

  var imageURL = $node.attr("src") || stripURLWrap($node.css('backgroundImage'));

  var imageUrlIsValid = imageURL.toLowerCase().split('?')[0].match(/\.jpg|\.png|\.gif/)

  if (!imageUrlIsValid) return;

  var nodeImage = new Image();
  nodeImage.src = imageURL;

  // images with a src width less than 1 are probably tracking pixels
  // so we want to ignore them.
  if (nodeImage.width > 1 || nodeImage.height > 1) {
    imageStats.push({
      efficiency: getPercentage( ($node.outerWidth() / nodeImage.width) )  + " / " + getPercentage( ($node.outerHeight() / nodeImage.height) ),
      displaySize: $node.outerWidth() + " x " + $node.outerHeight(),
      srcSize: nodeImage.width + " x " + nodeImage.height,
      srcURL: imageURL,
      node: node
    })
  }

});

console.table(imageStats);

The resulting stats will look something like this:
Picture

2 Responses
Add your response

Is this improving page loading at all? Why not use predefined sizes that can be stored and cached both on the client/server? It seems you are doing a lot of backend image processing which takes valuable server side time and resources. Besides dinamically generated images can't be cached by browser/web server unless you add dimensions to the url. Am I missing something?

over 1 year ago ·

The code snippet is only meant be a tool for measuring the efficiency of the images you are displaying. In our case, yes, the totality of what we do to load images improves the page load event time. We use javascript on the front end to ask the server for the best possible image, for whatever element needs and image...at that break point/size for that DPI/PPI/scale. We have sufficient resources to do all the fancy image processing on the server side, so no worries. But of course we cache the images on a cdn after we generate them, so only a maximum of 1 page load per break point / image size would incur any server side image work - most of which is done before the first user hits the page since our editorial team would have already previewed the article. And each image at each size generated has a unique url, there are no caching inefficiencies. The end result is that the blocking assets load first (html/css/essential js/etc) and we lazy load the best image possible asynchronously after the load event fires. So yeah, using this methodology our pages have a perceived decrease in load time VS say loading static images synchronously.

over 1 year ago ·