Responsive <img> elements in HTML, for Responsive Designs
Update: I have developed this idea much further, and a production-ready version is available for anyone to use over at Responsive-Images.com.
A bit of background
Responsive designs are becoming popular at the moment. The idea being that one website displays (and potentially behaves) differently dependent only upon the size of the screen it is being displayed on. A quick look at some of the examples on MediaQueri.es will show you what this means. On the left is what you’d see on a device like an iPhone, followed by a tablet device like the iPad in portrait mode, next is a base-line desktop or iPad in landscape, followed by a full desktop resolution. Same site, but re-jigged on each through the “magic” of CSS Media Queries.
For many site’s this is a great solution, though it won’t be appropriate for all cases. There are legitimate reasons for pointing a mobile user to a completely different site on a mobile sub-domain. Which technique is the most appropriate depends on the content and use case. If you want to know more about that I’d recommend reading this round-up of the arguments for Responsive or Mobile techniques.
There are a couple of caveats with Responsive designs however, and they’re mostly technical. Cross browser support is mostly a solved problem (I highly recommend grabbing a copy of the excellent Responsive Web Design, and while you’re at it it wouldn’t hurt to get Adaptive Web Design which is tangentially related and also excellent). There’s one major issue which remains - serving appropriately sized <img/>
elements to each design (usually for use with the Fluid Image technique).
The problem
Is fairly simple: small-screen sites only need small, low resolution <img/>’s. Large screen sites need large, high resolution <img/>’s. But the server has no way to know what resolution the client’s device is, so it can’t send the appropriately sized embeded images. You can for images supplied via CSS, because CSS has media queries. HTML currently has no such mechanism, and can’t know about the screen size to select an appropriate alternative source file.
An additional complication is the management of such images if you’re using a CMS. No one wants to hand-bake multiple resolutions of the same image. Likewise, there’s a heck of a lot of content that might already be in a CMS, so we could do with a solution that works dynamically on existing stuff rather than as an edit to the CMS itself. We want to retrofit responsive content images, not require a completely new CMS architecture.
There are some nice attempts at solutions, most tantalising to me is Filament Group’s experiment, which is a touch of brilliance. I think it can be improved a little bit though. It requires fiddling with HTML attributes on images you want to be responsive (which kills the idea of retrofitting to existing CMS content), and has a simple binary switch on whether an image is high resolution or low resolution. Considering that Media Queries are generally more granular than that, I’d rather take an approach where there’s an image sized specifically to each design/response. It seems to make more sense and strike a better balance between file size (bandwidth required) and image quality.
A solution
We can patch a solution while we wait for a HTML5 native method. To do that we need a touch of JavaScript, a couple of lines in a .htaccess file, and a small PHP script.
Here’s a run-through of the logic we want for this solution:
- Use JS to set a cookie with the current screen resolution bracket (320, 480, 960, etc)
- Catch all non-CSS image requests with a .htaccess rule and hand-over to a PHP script:
- If there isn’t a cookie, just deliver the requested image as normal, else:
- Use the cookie value as a path variable and check to see if an image of the same name exists at that path.
- If the image exists deliver that image, else:
- Check the default image folder to see if it exists there
- If it doesn’t exist, fire back a 404, else:
- Check the image dimensions
- If the source image is less than the width of the cookie variable, deliver the source image itself, else:
- Resize the source image to the width of the cookie variable
- Save the new file in the appropriate path
- Send the new file
- If there isn’t a cookie, just deliver the requested image as normal, else:
This provides the ability to retrofit a responsive design to an existing website, whilst also providing built in caching so the images don’t need to be generated on every request.
Entry Information
- Posted:
- Tue, 19th Jul 2011 at 23:07 UTC
- Filed under:
- Tags:
Comments
skip to comment formThanks for your all information. My friend had talk about HTML5 to me. But i haven't got opportunity to use.
I think this is a really good start, Matt. Despite how much of a PiTA it is to set up, I'd recommend switching to ImageMagick for image manipulation as it will allow for manipulation of any image type. My only other thoughts would be to move to fluid images (as you've mentioned), re-set the cookie on browser resize (as you've also mentioned), and to set some cache-related headers to get the browser to forgo re-requesting images that are already downloaded. I'd probably expire them on cookie expiration.
Thanks Aaron. The cache-headers isn't something I'd thought of - I'll look into that as soon as I get chance. ImageMagick was on my radar but I've not had a look yet - I was wanting to stick with the common PHP libraries but it might be worth seeing if I can fork the script so it'll use IM if installed, but fall back to the GD lib stuff otherwise. I'm not entirely happy with the quality of the re-scaling GD is producing.
Cool, the proof of concept seems to be ok, so I'll see how far I can refine it into something more production-ready Hopefully there will be updates on this soon.
What is the main purpose of the project? Reducing download time / improving speed? If so, did measure it if the request between htaccess, files, cookies and so on is faster than downloading a big picture? Im just curious in my attempt to find the best techniques for my first responsive designs
Thanks Matt. I have been trying to get my head around "responsive images" for quite a while now, I haven't understood why I couldn't just use CSS to resize the image, but having taken a look at this it all makes sense!
Looks to be an interesting technique.
I'm seeing issues though with reverse proxy caching. The use of a cookie to serve a request throws a spanner in the works - a caching mechanism such as Varnish would need to use the cookie value as part of the caching key. This will add to complexity.
Also, if you have rewritten your URLs for use with CDN, this technique will not work as the CDN can't do the cookie magic either.
One alternate solution would be to rewrite the image URLs client side. Don't have the rules in Apache, have them in JS. This way Apache, Varnish, CDN etc will get a pure URL with no cookie, making it possible to handle.