Today I thought I’d share a trick for offering retina (@2x) images on a blog where you don’t always have high-res images available.

The trick uses Apache rewrites and allows every image filename to be inserted in the HTML with “@2x” appended, falling back to the base filename if that file doesn’t exist. I also occasionally customize an additional format for social sharing, appending “_lg” instead of “@2x”, and the rules cascade such that if “_lg” doesn’t exist, it looks for “@2x”, and barring that, just uses the base filename.

My custom Jekyll image plugin adds the “@2x” automatically, so my tags include only the base name of the image. If I’m able to provide a high-res version, I just give it the exact same name, with “@2x” at the end, e.g. image1.png and image1@2x.png (and optionally image1_lg.png).

Here are the Apache rules from my .htaccess file:

# Image handling for opengraph meta
# Try @2x if _lg doesn't exist
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule (.*)_lg\.(jpg|png|gif) $1@2x.$2 [L]

# Fall back to base image file if no @2x
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule (.*)@2x\.(jpg|png|gif) $1.$2 [L]

To make life even easier, I have a Dropzone target that I can drop one or more images onto, and it will detect multiple versions (base, @2x, _lg) and output a single Jekyll (Liquid) tag for the set. (If you’re interested in that, let me know.)

My Jekyll image plugin also uses sips to automatically provide width and height attributes based on the lowest resolution image in the HTML output, ensuring that the image is displayed properly at different screen resolutions.

It’s a simple system, and possibly inefficient as it has to check for the existence of every image file during the load stage, but my tests don’t indicate any noticeable latency in the process. I can’t guarantee that would scale to more image-heavy sites, but it makes life easy for me on this blog.