Automatic Conditional Retina Images

One line of JavaScript and a few mod_rewrite rules and we have no fuss Automatic Conditional Retina Images. No DOM crawling. No redundant requests. No server-side scripts. No cookies? No problem, they just get the original image. The only change you might need to make to your workflow is explicitly defining image width and height in HTML (you should really be doing this already) and background-size in your CSS. And of course, creating retina images. If your original image is named circle.png the retina version should be circle@2x.png If you forget a retina image the original image will be served, even on retina devices. Check the caveats.

The JavaScript

if((window.devicePixelRatio===undefined?1:window.devicePixelRatio)>1)
	document.cookie='HTTP_IS_RETINA=1;path=/';

I think this must be placed inline in the head (not included in an external JavaScript file) and before any external CSS or images in order for the cookie to be set before any images are requested but I'd be happy to be wrong. Add it to a template or at the very least use some sort of server-side include in case you need to update this in the future.

The Mod Rewrite

Add this to an .htaccess file in the directory where you keep your images:

<IfModule mod_rewrite.c>
	Options -MultiViews
	RewriteEngine on
	RewriteCond %{HTTP_COOKIE} HTTP_IS_RETINA [NC]
	RewriteCond %{REQUEST_FILENAME} !@2x
	RewriteRule ^(.*)\.(gif|jpg|png)$ $1@2x.$2
	# if @2x isn't available fulfill the original request
	RewriteCond %{REQUEST_FILENAME} !-f
	RewriteRule ^(.*)@2x\.(gif|jpg|png)$ $1.$2
</IfModule>

In HTML



Be sure to specify width and height of the original (non-retina) image. eg.

<img src="circle.png" width="240" height="240" alt="">

Or in CSS

Be sure to specify the background-size property using the width and height of the original (non-retina) image. eg.

background-image:url(circle.png);
background-size:240px 240px;

Prior Art & Caveats Pointed Out Post Posting

Lots of reports of future browsers preloading images before the cookie can be set. I'm not seeing this on the iPad 3, 4th generation iPod touch, or the retina MacBook Pro, which are my current primary concerns but I respect they may not be yours. Apparently IE9 does not block while it processes inline JavaScript (currently moot since it doesn't run on a retina device). Firefox 14.0.1 on a retina MacBook Pro does not load the @2x images because it does not support window.devicePixelRatio and checking min-resolution with window.matchMedia().matches seems wonky.

Shaun Inman might have been crazy mid-2012.