Craig Russell

Web n That

I ♡… the web… php… html… css… linux… shell scripting… folding paper… dog walking… sandwiches… being outside… and most of all @vicuol ☺

Responsive Images and Context Aware Image Sizing

January 22nd, 2011

I’ve been thinking about building responsive web sites lately. This has lead me down the path towards fluid image scaling and on to the problem of serving appropriately sized images for the client platform. In other words, how can we serve up small scale images for mobiles and tablets and larger images for desktops?

Fluid image scaling alone is not sufficient, mobile clients can’t be expected to download a 1000px wide image then scale it down to 200px wide. This is both slower and more tariff hungry than necessary.

The immediate solution is to use media queries to swap out different scaled images for different display sizes. But this is cumbersome to manage on a large scale and offers no robust solution when using the SRC attribute of the IMG element.

I’m not the only one to recognise this as an issue for responsive we design. In the course of my research I came a cross this article by the Filament Group, proposing another solution to the problem. The Filament Group method uses .htaccess files and some JS to serve up different sized images based on the screen width.

I’ve developed a technique that uses a server side script (in PHP) to serve up images of several different resolutions. It requires only a small amount of JavaScript and can scale quite easily.

Within the PHP script is a nested array that lists images files and their relative percentage scales. The array is structured such that each image is assigned a URL safe id (‘puppy’ in the example). For each image file the nested array describes the file’s scale. The largest image has a scale of 100 down to the smallest at 0. The 0 scale image is initially loaded by the browser, so in the example this is a 1×1 pixel transparent PNG.

1
2
3
4
5
6
$images['puppy'][100]      = 'puppy_1280x960.jpg';
$images['puppy'][75]       = 'puppy_960x720.jpg';
$images['puppy'][50]       = 'puppy_640x480.jpg';
$images['puppy'][25]       = 'puppy_320x240.jpg';
$images['puppy'][10]       = 'puppy_128x96.jpg';
$images['puppy'][0]        = 'clear_pixel.png';

The PHP script serves up an images file based upon two GET parameters, id and scale. The script returns the first file that is greater than the requested scale. So a URL like …/getimage.php?id=puppy&scale=47 will return the image at scale 50. If no scale is specified the 0 scale image is returned. This is important, I’ll explain why in a bit.

In the HTML file the image SRC attribute is set to get the requested image id, but with no scale specified. The CSS ensures that the image scales fluidly within it’s container. A bit of JavaScript calculates the percentage width of the image relative to the maximum width of the container. This figure is appended to the end of the SRC attribute as the scale parameter.

Taking this information, the server returns the appropriately scaled image for the width of the image element. So mobile browsers will download smaller image files than desktops. The only overhead is the initial request for the 0 scale image, which is why I’ve set it to a clear pixel.

It goes without saying that the image data need not be stored in an array, a data base would probably be better and certainly easier to integrate with a CMS.

Also, while I’ve use a relative scaling measure (0-100) the same affect would be achieved when using absolute width measurements. There’s pros and cons to each approach, I’ll leave you to judge.

An demo page is set up here and the source is up on GitHub. This is far from polished, so any comments, criticisms or suggestions are more than welcome.

  • Bart

    Great trick!
    But what about browsers with javascript disabled?
    They only see the scale 0 image (no image).

    Regards,
    Bart.

  • http://www.we-are-gurus.com Remi Grumeau

    This is a good idea, nothing new here btw even if you can do the same using plain Javascript instead of relying to a server-side script, moreover if this server-side code is not used to generate the needed w/h image from HD on-the-fly (w/ cache)

    Here is the biggest cons to me:
    #1 no manifest caching (which creates #2)
    #2 no offline mode (since you need a server access for each image)
    #3 too much HTTP & Apache threads
    #4 no scalability
    #5 your clear pixel is what SEO would see: fail

    If you really want to do this in PHP, use dynamic w&h values, generate the image using GD and store it in a folder. Each time, test if file exists before generating it again. This will support iPad2 2048×1536 retina screen to oldest 240×160 Crapberry’s ones.

    If you follow closely your analitycs and see you have 3 majors screens size/ratio, the you can use header meta width:device-width + and JS array to choose between one of the post-generated 3 sizes TO REPLACE TO LOWEST ONE (which would be 1 or 2kb) search robots & non JS feature-phones.

    btw, i love your “Woadkill Wabbit” :)

    R.

  • Craig

    @Bart
    You’re absolutely correct about non js browsers, which is why I left the 0 scale image configurable. I suppose you could put a low-res image in instead – I dunno?

    @Remi
    You make a lot of valid points.

    On the fly image generation is a great idea, but could potentially create an enormous set of image files, which is why I chose to map between relative scale and absolute width.

    There’d definitely need to be some off-line cache. I left this out for now, purely because this is just a concept sketch. I have pencilled it in for a later revision.

    Not sure I agree with you about there being no scalability?

    And of course, you could JS the whole thing.

    Cheers for your feedback. Tis much appreciated :D

  • http://www.the-art-of-web.com/ Duncan

    Apache ModPagespeed will automatically scale and cache images based on the width/height attributes.

  • Craig

    @Duncan
    Good call. If your hosting provider offers it, Mod_pagespeed could do a lot of the optimisation work for you.

  • http://www.preeminentproductions.com Anthony

    Very nice! Bookmarked! Trying to soak up as much info as I can, on all this new talk of responsive and media queried design.

  • http://www.deeson.co.uk/online Alli

    Hi,

    It’s great to see the community jumping on board with solutions to dynamically reduce things like image size dependent on the client device.

    Have you seen http://tinysrc.net/ ?

    This is a fairly similar approach to what you’re achieving here. It also has the advantage of not requiring JS.

  • Craig

    @Anthony
    Cheers for the comment. With the diversity of platforms now available it’s becoming quite an exciting time for the web.

  • http://filamentgroup.com Scott

    Thanks for the followup to our technique, Craig. Using PHP to generate the image sizes seems like a decent approach for maintenance sake.

    However, I hope you don’t mind if I offer a little criticism. The explanation of our article doesn’t quite describe the reasoning for particular approach we took, which is providing a meaningful mobile-optimized image in the HTML, and enhancing it on larger screens without requesting both image sizes. By removing the .htaccess and the JS-generated base element from our technique, it’s impossible to serve a mobile-friendly image in the markup from the start while ensuring larger screen users do not download both image sizes (because JS alone can not prevent that first request from going out to the server). This point is critical to the approach. Simply defaulting to an empty image in the HTML means users on many feature phones (or any browser with JavaScript unavailable or disabled, and search engines as well) will receive no image at all.

    Have you considered using our responsive images technique as it is and simply referencing two different php-generated image sizes in the markup? It seems that would be more in-line with the accessibility & performance goals we set out to achieve. We’d welcome contributions and ideas in the github repo (http://bit.ly/g09bGo )

    Cheers!

  • vinay

    nice! even though this effect can be obtained through js, this is just another way of the webdesigner community to say- “we shall leave no milestone unturned”

  • Craig

    @Alli
    I hadn’t seen tinySrc before, I’ll have to have a play with that.

    @Vinay
    I think of it as natural selection for ideas.

    @Scott
    The default image can be set to any file, I’ve just used a 1px image for the 0 scale. I see how your method prevents this double loading problem, which is obviously preferable. What’s missing in IE/Fx to fully support it?

  • Pingback: » [Friday Links] The HTML Edition - Wayne State Web Communications Blog

  • Pingback: La veille du week-end (quinzième) | LoïcG

  • WerbungnuMarctrixrhierher

    Nothing worse than webpages, that do not look on my iPhone, the way I know them from my desktop!!!

  • http://www.videomarketinggoldmine.co.uk Video Marketing Goldmine

    I have the same question as Bart

  • http://twitter.com/Lucanos Luke

    {Comment Withdrawn}

  • Pingback: Responsive Images | Naga IT Services

  • Pingback: level. a small grafik design boutique agency based in weymouth dorsetlevel. grafik design boutique

  • mairead

    We loved the filament group solution too but we wanted to provide more browser support so we created our own hack using noscript instead. It works even though it feels a bit wrong. You can check out the article here: http://www.headlondon.com/our-thoughts/technology/posts/creating-responsive-images-using-the-noscript-tag and github here: https://github.com/futurechimp/responsive_image_tag

  • Pingback: Brave Knowledge » Smashing Magazine Responsive Web Design Techniques, Tools and Design Strategies

  • Pingback: Responsive IMGs Part 2 — In-depth Look at Techniques « Cloud Four

  • Pingback: Responsive web design, the magic of CSS3 Media Queries – William Owen