A few weeks ago, we announced that oxidedesign.com was fully retina optimized. For those of you who do not know, a retina display is a monitor or device that has more pixels per inch of space than a normal display. This basically means it is harder to tell where the edges of pixels are, allowing for an extremely crisp and clean appearance. This works great on the web for things like text, but a problem arises when displaying images. Since a typical image is built for standard displays, a retina display essentially has to size-up the image to display it. This usually doesn’t end great, especially next to super crisp text.

The solution for retina displays is to serve a larger image, commonly an image that is twice the resolution of the original image, in place of the original image. The real problem arises when you start to look at file sizes, bandwidth requirements, and page load times. When you double the resolution of an image, you quadruple its file size. This means big problems for oxidedesign.com. I already spent quite a good long time getting our image-heavy site to be relatively efficient when it comes to loading and bandwidth, and I wasn’t about to throw that all away.

I need to be able to detect a retina display and I need full control of the content that is being served.

Ideally, I would detect a retina display from the server-side, unfortunately there isn’t any way for a server to know what type of display you are using yet. What you can do is detect a retina display from the front-end using JavaScript. Turns out that every modern browser will return a variable called the Device Pixel Ratio. If the Device Pixel Ratio is 2 or larger, then the website is being viewed using a retina display.

A small amount of research will reveal that there is a whole host of JavaScript plugins and libraries that will do this for you, and through one method or another they will serve the high resolution images in place of the original images. I am here to tell you that the methods that those scripts use are fundamentally flawed and you should not use them if you don’t have to. We’re already loading larger images, so loading them in after the original images have already loaded and swapping them out after the page has loaded is just adding insult to injury.

Knowing that swapping images out on the front-end is absolutely not good enough, I needed to find a way to send the Device Pixel Ratio variable to the server. That way, I would have control over what image is being loaded in the first place. Server-side detection also allows me to tell the site to serve fewer posts at a time to counteract the larger load times and save you from burning up your phone’s entire data plan by visiting our homepage a couple times. So what could I use to send a variable from your browser to our server? That’s right, kids, we’re going to use a Cookie!

Time to dive into the code

In order to detect the Device Pixel Ratio and write it into a Cookie, we only need two very short and simple lines of code:

var retina = 'retina='+ window.devicePixelRatio +';'+ retina;
document.cookie = retina;

All that code does is retrieve the Device Pixel Ratio and saves it into a simple variable, then applies it to the page as a Cookie. After a cookie has been written in this fashion, the next time a page is requested, we can tell the server to look for that cookie and serve our retina-optimized content. Alone, the aforementioned line of code would write the Cookie as expected, but since the server has already sent the entire page to the browser, we wouldn’t get a retina-optimized page on the first shot.

In order for this to really work, we need to force a page refresh after the Cookie is written:

var retina = 'retina='+ window.devicePixelRatio +';'+ retina;
document.cookie = retina;
document.location.reload(true);

It isn’t the most ideal situation, but it is a whole lot better than loading a bunch of unnecessary images, and since a browser will fire JavaScript as soon as it is loaded, if we put this script at the very top of the document, the page will refresh before anything else is loaded. Adding this creates a new problem, though, because if it is just sitting up at the top of the page, firing every time the page loads, we’ve just created a really terrible refresh loop which will constantly re-write the same cookie over and over again and never let our page actually load. The trick to this whole thing is using that code in the appropriate spot, and making it smarter by utilizing some server-side conditions.

Detecting the presence of a cookie in PHP is very simple. Since you can get a Cookie using the superglobal variable $_COOKIE, we can get our retina Cookie by asking for $_COOKIE['retina'].

Using that, we can set up a condition that tests whether the cookie is set, and if it is, do whatever we want (in my case, simply set a variable to “true”, which I then use later throughout the template), but if it isn’t, output the JavaScript which sets the cookie and refreshes the page:

<?php if ( isset( $_COOKIE['retina'] ) ) {
	$ratio = $_COOKIE['retina']; if( $ratio >= 2 ) { $retina = true; }
} else { ?>
<script type="text/javascript">
	var retina = 'retina='+ window.devicePixelRatio +';'+ retina;
	document.cookie = retina;
	document.location.reload(true);
</script>
<?php } ?>

But what about the weirdos who disable Cookies?

Yes, this means that if a user has Cookies disabled, they won’t get retina content. This is an edge-case that I am comfortable with, since almost nobody browses with Cookies disabled these days. One little bug which needs to be addressed does indeed arise if the user has Cookies disabled, though. Since the cookie is never written, we run into the refresh loop issue again, and while I’m comfortable with users who have Cookies disabled not getting retina-optimized images, I’m certainly not comfortable with them being unable to view our site all-together. Fortunately for us, modifying the line of code which refreshes the page with a simple condition that checks for the existence of the cookie that we just attempted to write will spare us here.

var retina = 'retina='+ window.devicePixelRatio +';'+ retina;
document.cookie = retina;
if ( document.cookie.length !== 0 ) { document.location.reload(true); }

There you have it!

This, to date, is the best way I can come up with to detect a retina display and serve appropriate content in the most efficient fashion possible. Hopefully in the future as the technology is adopted and matures there will be a better way to do this, but for now this method will work really well and has proven to work not only for our website, but is running on several of our clients’ sites.