Responsive images

Responsive design is one of the hot topics in the web development these days. there isn’t “the correct” solution invented yet.

a lot can be achieved by media queries but one thing is still not properly solved, responsive images.

the problem: we want to eliminate loading unnecessary big images on mobile devices and slow connection, we want to serve bigger images for retina like  (high resolution) devices

there is a great presentation done by mr @Falkowski on this topic. one of the solution he mentioned was adaptive images

 

Adaptive Images

pros:

  • just the required images are served, no additional requests
  • easy to use
  • doesn’t require editing markup

cons:

  • image resize done on the fly – hitting php
  • proposed solution is not easily scalable across multiple servers (cached images must be shared across multiple servers, if in use)
  • CDN is not supported
  • potential slowdown of page rendering while javasctipt in the header is executed (this have to be measured)
  • extra cookie within every request
  • ignores window resize

my improvements:

  • generate images upfront, or use HttpImageFilterModule
  • do detection on server level, f.e. in nginx – serve proper image based on the cookie

cons of my implementation:

  • different image content is served per device under the same url (browser specific content all over again ?!)
  • we can do redirect on server level to solve the above point but the price is another connection from the device – not ideal

 

Context-Aware Image Sizing 

another solution is to use javascript to overwrite all the image urls and make them link to the proper location. this solution goes one step further and implements BASE html element.

pros:

  • it works

cons:

  • redirects on language level – in php
  • changing DOM – it has to wait until the DOM is fully loaded, than and than it has to refresh it

requirements:

  • javascript in the header has to be inlined otherwise it is not reliable on FF (possibly IE) as its subject to race conditions

however other research project on this subject abandoned BASE tag solution as they didn’t want to use inline  javascript in the head.

 

My idea

combining the two methods above i’ve created my solution. the idea is to use inline javascript detection in the header and set BASE meta tag to point to proper location to load correct images. the solution handles inline images as background images are handled by media queries.

pros:

  • CDN  can be used
  • just one request per image
  • no server/language level detection
  • no extra cookies
  • no DOM manipulation

cons:

  • potential slowdown of page rendering while javasctipt in the header is executed (this have to be measured, anyone?)
  • no browser speed detection  (is this even reliable? isn’t it the measurement slowing the page more than it speeds it up?)

neutral:

  • can’t set image dimensions in HTML but this can be done in CSS via media query
  • for people without javascript (is this even happening outside of desktop world?) will receive medium images (they are get used to reduced functionality), or we can assume that they are coming from desktop and serve them proper images.

requirements:

  • inlined javascript in the header
  • only images for what we want to change dimensions should have relative URL and be affected by BASE, everything else should have absolute URL
    this is quite easily done in Magento by changing default image rendering such as: $this->helper('catalog/image')->init($_product, 'image') for './media/catalog/product/'.$_product->getData('image')

what about window resize?

we can not resize browser on mobile/tablet device (or at least for now) and only developers dramatically resize browser window on desktop (i dont have data for this, i would be thankful to anyone who can prove/disprove this), so we can assume that image initially loaded doesn’t have to be changed.

note: it’s not possible to change BASE href property via javascript. or at least not in chrome and firefox. we should remove base tag once the page is rendered, as new images created via javascript will be affected by it. CSS in external files is not affected.

Demo and Demo.zip

 

Foresight.js

pros (taken from their website):

  • Request hi-res images according to device pixel ratio
  • Estimates network connection speed prior to requesting an image – this is somewhere between pros/cons as it has to delay rendering to determinate connection speed if the DOM is rendered fast
  • Allows existing CSS techniques to control an image’s dimensions within the browser this is not feature of this solution, it is general feature
  • Implements image-set() CSS to control image resolution variants more of a hack than a feature, image-set() is meant to be used for background images
  • Does not make multiple requests for the same image
  • Javascript library and framework independent (ie: jQuery not required) this is expected from every solution
  • Image dimensions set by percents will scale to the parent element’s available width this is expected from every solution
  • Default images will load without javascript enabled  this is expected from every solution
  • Does not use device detection through user-agents this is their decision, not a feature
  • Minifies to 7K this is expected from every solution
  • http://junkyard.damowmow.com/507

cons:

  • requires changes to markap – adding special attributes and noscript tag for every image
  • DOM manipulation executed on window onload

 

picturefill

pros:

cons:

  • requires changes to markap – adding additional divs, special attributes and noscript tag for every image – the messiest markup solution
  • DOM manipulation executed on window onload

 

Conclusion

So far i like my solution in combination the best.

  • no extra cookie set for every request
  • minimum changes to markup (depends on the system you are using)
  • no DOM manipulation, no extra waiting – apart from waiting to render the initial javascript
  • direct CDN load – if images are pre-rendered
  • one request per image
  • image sizes can be defined in the application on the front-end (in detecting JS), not in the backed or on the server
  • we can create server side fallback for CDN request. (f.e. CloudFront flow: browser <image size detection -> CDN <- caching detection -> server side file <- resizing image and sending it back to CDN to cache it>)

 

Comments?

 

another great blog post on this topic written by Paul Stamatiou.

Leave a Reply