Decodize

console.log

Simple Responsive Image Technique

RWD (Responsive Web Design) is increasingly popular over past few years. One important problem faced by RWD is lack of a standardised solution to deliver resized images into multiple devices. We have wide range of device categories, screen resolutions, pixel densities and lack of bandwidth/connection detection methods, all made this process difficult. There is no simple silver bullet to solve this issue.

This is a quick post on a simple technique I used to create responsive image. This is a javascript solution, but it will work in javascript disabled environment by using a noscript fallback. This technique will start with mobile image first & there is no need to parse and replace image sources.

I’m using google picasa as my image host. I can resize images dynamically by setting width/height in the url.

Responsive images demo

Eg: //lh3.googleusercontent.com/-Rw0hpxt70co/ULeX80ncW3I/AAAAAAAAE6g/kIDj6u1zdyI/s640/query-loader1.jpg

Setting s320 will create image with width/Height (resize proportionally) 320px. We can also pass width or height. Setting w320 will create an image with width 320px or passing h320 will constrain height of dynamically created image to 320px. Now we have our server, which can provide us different images sizes upon request.

You can use your own server methods or other resources like src.sencha.io to resize images on the fly.

Technique

Using css fluid image technique scale image to viewpot. Get the device size and insert image using script.

CSS

1
2
3
4
5
img {
  display: block;
  border: 0;
  max-width: 100%;
}

JavaScript

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<script>
    var cwResImg = function () {
  var cwBpArry = [1382, 992, 768, 480], //Image breakpoint arrays
      currIndex,
      cwResImgVal = Math.max(screen.width,screen.height),
      hdpi = window.devicePixelRatio > 1 ? window.devicePixelRatio : 1,
      rwdImgId = "rwdimg-"+Math.floor(Math.random()*1000),
      tpl='<img src="{src}" alt="{alt}" title="{title}" id="{rwdImgId}" {attributes}>';

  cwBpArry.push(cwResImgVal);
  cwBpArry.sort(function(a,b){return a-b});

  if(Array.prototype.indexOf){
      currIndex = cwBpArry.indexOf(cwResImgVal) + 1;
  }else{
      for(var i in cwBpArry){
          if(cwBpArry[i] === cwResImgVal){
              currIndex = parseInt(i)+1;
          }
      }        
  }

  cwBpArry[currIndex] = cwBpArry[currIndex] || cwBpArry[currIndex-1];

  var imgWid = Math.max.apply(Math, cwBpArry) <= cwBpArry[currIndex] ? cwBpArry[currIndex-2] : cwBpArry[currIndex];

  return {
      imgWid : imgWid,
      hdpi: hdpi,
      id:rwdImgId,
      rwdImg:function(arg){
          
          var src = arg.src || arguments[0] || '',
              src = src.replace(/\/s\d*\//, '/s'+imgWid * hdpi+'/'), //picasa image size replacing (s340 to device width)
              title = arg.title || arg.alt || arguments[1] || '',
              alt = arg.alt || arg.title || arguments[2] || arguments[1] || '',
              attributes = arg.attr || arguments[3] || '',
              img = tpl.replace('{src}',src).replace('{title}',title).replace('{alt}',alt).replace('{rwdImgId}',rwdImgId).replace('{attributes}',attributes);
              document.write(img)
      }
  };
}()
</script>

Paste it in your page header. This will set width of the screen into ‘cwResImg’ variable. You can set image breakpoints in this variable cwBpArry = [1382, 992, 768, 480];

HTML
Replace images in HTML with.

1
2
3
4
5
6
7
8
9
10
<noscript>
  <img src="http://lh6.googleusercontent.com/-nI33VLdtmFo/UN9MmPN6bHI/AAAAAAAAFEE/1uJBJ7-plEs/s720/Webpagetest-IE8-Octopress-Default-waterfall.png" alt="Responsive images test">
</noscript>
<script>
  cwResImg.rwdImg("http://lh6.googleusercontent.com/-nI33VLdtmFo/UN9MmPN6bHI/AAAAAAAAFEE/1uJBJ7-plEs/s450/Webpagetest-IE8-Octopress-Default-waterfall.png", 'Responsive images text script');

  ---or----

  cwResImg.rwdImg({src:'http://lh6.googleusercontent.com/-nI33VLdtmFo/UN9MmPN6bHI/AAAAAAAAFEE/1uJBJ7-plEs/s450/Webpagetest-IE8-Octopress-Default-waterfall.png', alt:'Responsive images text script', title:'Responsive images text script'});
</script>

It has two parts
1) noscript tag contains a standard image for fallback. If js is not supported, this image will show.

2) Script part
Syntax

1
2
3
cwResImg.rwdImg("src","alt","title","class='myclass'");
or
cwResImg.rwdImg({src:"src", alt:"alt",title:"title",attr:"class='myclass'"})
1
cwResImg.rwdImg("http://lh6.googleusercontent.com/-nI33VLdtmFo/UN9MmPN6bHI/AAAAAAAAFEE/1uJBJ7-plEs/s450/Webpagetest-IE8-Octopress-Default-waterfall.png","Responsive images text script","Responsive images text script");

JavaScript variable ‘cwResImg’ will replace by the max width of the device.

When page loads url will be like the following, if its a desktop with resolution more than 1382px

//lh6.googleusercontent.com/-IdiwvKGQ8Lk/UN9KOZvdW7I/AAAAAAAAFDk/iSvy1_SZrrM/s1382/RTT%2520Decodize%2520github.png

Demo

Responsive images

Performance and Bandwidth

After including this there is a noticeable performance improvement in iPhone waterfall view.

Before (11.866s)

After (8.841s)

Drawbacks
Messy HTML.
Accessibility