So you’ve been building some responsive designs and you’ve been working through your checklist of things to do:
- You started with the content and designed around it, with mobile in mind first.
- You’ve gone liquid and there’s nary a px value in sight; % is your weapon of choice now.
- You’ve baked in a few media queries to adapt your layout and tweak your design at different window widths.
- You’ve made your images scale to the container width using the fluid Image technique.
You’ve done a good job so pat yourself on the back. But there’s still a problem and it’s as tricky as it is important: image resolutions.
HTML has an
CSS is great at adapting a website design to different window sizes – it allows you not only to tweak layout but also to send rescaled versions of the design’s images. And you want to do that because, after all, a smartphone does not need a 1,900-pixel background image1.
HTML is less great. In the same way that you don’t want CSS background images to be larger than required, you don’t want that happening with
<img>s either. A smartphone only needs a small image but desktop users need a large one. Unfortunately
<img>s can’t adapt like CSS, so what do we do?
Well, you could just use a high resolution image and the fluid image technique would scale it down to fit the viewport; but that’s sending an image five or six times the file size that’s really needed, which makes it slow to download and unpleasant to use. Smartphones are pretty impressive devices – my ancient iPhone 3G is more powerful in every way than my first proper computer – but they’re still terribly slow in comparison to today’s desktop machines. Sending a massive image means it has to be manipulated in memory and redrawn as you scroll. You’ll find phones rapidly run out of RAM and slow to a crawl.
Well, OK. You went mobile first with everything else so why not put in mobile resolution
<img>s too? Because even though mobile devices are rapidly gaining share in your analytics stats, they’re still not likely to be the major share of your user base. I don’t think desktop users would be happy with pokey little mobile resolution images, do you? What we need are adaptive images.
Adaptive image techniques
There are a number of possible solutions, each with pros and cons, and it’s not as simple to find a graceful solution as you might expect.
src attribute, and then the browser will request that new image too. Not instead of, but as well as. Not good: that’s added more bloat instead of cutting it.
There’s a detailed round-up of potential techniques for solving the adaptive images problem over at the Cloud Four blog if you fancy a dig around exploring all the options currently available. But I’m here to show you what I think is the most flexible and easy to implement solution, so here we are.
Adaptive Images aims to mitigate most of the issues surrounding the problems of bringing the venerable
So, what does this solution do?
- It allows
<img>s to adapt to the same break points you use in your media queries, giving granular control in the same way you get with your CSS.
- It installs on your server in five minutes or less and after that is automatic and you don’t need to do anything.
- It generates its own rescaled images on the server and doesn’t require markup changes, so you can apply it to existing web content.
Sound good? I hope so. Here’s what you do.
Setting up and rolling out
I’ll assume you have some basic server knowledge along with that wealth of front-end wisdom exploding out of your head: that you know not to overwrite any existing .htaccess file for example, and how to set file permissions on your server. Feeling up to it? Excellent.
- Download the latest version of Adaptive Images either from the website or from the GitHub repository.
- Upload the included .htaccess and adaptive-images.php files into the root folder of your website.
- Create a directory called ai-cache and make sure the server can write to it (
CHMOD 755should do it).
<head>of your site:
That’s it, unless you want to tweak the default settings. You likely do, but essentially you’re already up and running.
How it works
Adaptive Images does a number of things depending on the scenario the script has to handle, but here’s a basic overview of what it does when you load a page running it:
- A session cookie is written with the value of the visitor’s screen size in pixels.
- The HTML encounters an
<img>tag and sends a request to the server for that image. It also sends the cookie, because that’s how browsers work.
- Apache sits on the server and receives the request for the image. Apache then has a look in the .htaccess file to see if there are any special instructions for files in the requested URL.
- There are! The .htaccess says “Hey, server! Any request you get for a JPG, GIF or PNG file just send to the adaptive-images.php file instead.”
- The PHP file then does some intelligent thinking which can cover a number of scenarios, but I’ll illustrate one path that can happen:
- The PHP file looks for the cookie and finds out that the user has a maximum screen width of 480px.
- The PHP has a look at the available media query sizes that were configured and decides which one matches the user’s device.
- It then has a look inside the /ai-cache/480/ folder to see if a rescaled image already exists there.
- We’ll pretend it doesn’t – the PHP then goes to the actual requested URI and finds that the original file does exist.
- It has a look to see how wide that image is. If it’s already smaller than the user’s screen width it sends it along and stops there. But, let’s pretend the image is 1,000px wide.
- The PHP then resizes the image and saves it into the /ai-cache/480 folder ready for the next time someone needs it.
It also does a few other things when needs arise, for example:
- It sends images with a cache header field that tells proxies not to cache the image, while telling browsers they should. This avoids problems with proxy servers and network caching systems grabbing the wrong image and storing it.
- It handles cases where there isn’t a cookie set, and you can choose whether to then send the mobile version or the largest configured media query size.
- It compares timestamps between the source image and the generated cache image – to ensure that if the source image gets updated, the old cached file won’t be sent.
There are a few options you can customize if you don’t like the default values. By looking in the PHP’s configuration section at the top of the file, you can:
- Set the resolution breakpoints to match your media query break points.
- Change the name and location of the ai-cache folder.
- Change the quality level any generated JPG images are saved at.
- Have it perform a subtle sharpen on rescaled images to help keep detail.
- Toggle whether you want it to compare the files in the cache folder with the source ones or not.
- Set how long the browser should cache the images for.
- Switch between a mobile-first or desktop-first approach when a cookie isn’t found.
More importantly, you probably want to omit a few folders from the AI behaviour. You don’t need or want it resizing the images you’re using in your CSS, for example. That’s fine – just open up the .htaccess file and follow the instructions to list any directories you want AI to ignore. Or, if you’re a dab hand at
RewriteRules you can remove the exclamation mark at the start of the rule and it’ll only apply AI behaviour to a given list of folders.
As I mentioned, I think this is one of the most flexible, future-proof, retrofittable and easy to use solutions available today. But, there are problems with this approach as there are with all of the ones I’ve seen so far.
This is a PHP solution
I wish I was smarter and knew some fancy modern languages the cool kids discuss at parties, but I don’t. So, you need PHP on your server. That said, Adaptive Images has a Creative Commons licence2 and I would welcome anyone to contribute a port of the code3.
Content delivery networks
Adaptive Images relies on the server being able to: intercept requests for images; do some logic; and send one of a given number of responses. Content delivery networks are generally dumb caches, and they won’t allow that to happen. Adaptive Images will not work if you’re using a CDN to deliver your website.
A minor but interesting cookie issue.
<img> tags. That could mean images being requested without a cookie being available. Adaptive Images has a two-fold mechanism to avoid this being a problem:
$mobile_firsttoggle allows you to choose what to send to a browser if a cookie isn’t set. If
FALSEthen it will send the highest configured resolution; if
TRUEit will send the lowest.
- Even if set to
TRUE, Adaptive Images checks the User Agent String. If it discovers the user is on a desktop environment, it will override
$mobile_firstand set it to
This means that if
$mobile_first is set to
TRUE and the user was unlucky (their browser didn’t write the cookie fast enough), mobile devices will be supplied with the smallest image, and desktop devices will get the largest.
For today, this is a pretty good solution. It works, and as it doesn’t interfere with your markup or source material in any way, the process is non-destructive. If a future solution is superior, you can just remove the Adaptive Images files and you’re good to go – you’d never know AI had been there.
However, this isn’t really a long-term solution, not least because of the intermittent problem of the cookie and image request race condition. What we really need are a number of standardized ways to handle this in the future.
First, we could do with browsers sending far more information about the user’s environment along with each HTTP request (device size, connection speed, pixel density, etc.), because the way things work now is no longer fit for purpose. The web now is a much broader entity used on far more diverse devices than when these technologies were dreamed up, and we absolutely require the server to have better knowledge about device capabilities than is currently possible. Relying on cookies to do this job doesn’t cut it, and the User Agent String is a complete mess incapable of fulfilling the various purposes we are forced to hijack it for.
Secondly, we need a W3C-backed markup level solution to supply semantically different content at different resolutions, not just rescaled versions of the same content as Adaptive Images does.
I hope you’ve found this interesting and will find Adaptive Images useful.
1 While I’m talking about preventing smartphones from downloading resources they don’t need: you should be careful of your media query construction if you want to stop WebKit downloading all the images in all of the CSS files.
2 Adaptive Images has a very broad Creative Commons licence and I warmly welcome feedback and community contributions via the GitHub repository.
3 There is a ColdFusion port of an older version of Adaptive Images. I do not have anything to do with ported versions of Adaptive Images.