17.Sep.2010 Retina display and web development
A couple of days ago I got a new toy, an iPod touch 4th gen, that has the new high resoultion 960×640 display. I have been having higher resolutions in mind since I started development of Orbium, the source art is high res and I scale it down for different devices.
So this should be straightforward right? Not quite. For the Retina display Apple has choosen, for backwards compability with the older iPhones 480×320 display, to make “1px” in CSS to be 2 real hardware pixels. That means that every site developed for the older models look exactly the same on the new iDevices with retina display. It is ofcourse good for backwards compability, but we want to use the new high res display to its full potential.
Fortunately, you can detect this from JavaScript in the window.devicePixelRatio variable. In the case of the new Retina display equipped iDevices this is set to 2. I am unaware of any other device that currently implement this, but thanks to the dynamic powers of JavaScript we can detect if this property exists, and use a default value of 1 if it doesnt. So we define the following utility function:
function getDevicePixelRatio() {
if (window.devicePixelRatio == undefined) {
return 1;
}
return window.devicePixelRatio;
}
By using this utility function, we can decide how to do our layouts, what image sizes to use, and what dimensions objects in the page should have. Now everything is high res on the iPhone4 etc and all is good. Only one problem left to solve: only 1/4 of our page is visible on the screen! Why? The device has twice the pixel density than the older iDevices, and hence four times as many pixels.
What to do? I can think of several solutions, but I only ended up trying one, since it worked soo good: manipulating the scale property of the viewport meta tag. Instead of declaring the viewport tag in HTML we leave its contents empty like so:
<meta id="vp" name="viewport" content=""/>
Note that I have also given it an id “vp”. Then somewere in the initilalization code for the page we do this:
var vp = document.getElementById("vp");
var vp_width = "width=device-width, ";
var vp_user_scalable = "user-scalable=no, ";
var scale = "1.0";
if (getDevicePixelRatio() == 2) {
scale = "0.5";
}
var vp_initial_scale = "initial-scale="+scale+", ";
var vp_minimum_scale = "minimum-scale="+scale+", ";
var vp_maximum_scale = "maximum-scale="+scale;
vp.attributes.content.value = vp_width+vp_user_scalable+
vp_initial_scale+vp_minimum_scale+vp_maximum_scale;
So what happens here? we build up the viewport tag dynamically and set the scale property to 0.5 if we have a pixel density of 2. This “zooms out” the page so we see the whole page. Initially I was worried that this would kill performance, in about the same way that happens if you use the scle property on the canvas tag. But if it is set to exactly 0.5 it is not a problem, as it will give a pixel perfect result. I tried to set it to for example 0.51 to see what happens, and the result was jerky animation and a very hot device.
The result is awesome, performance is great, and the higher dpi graphics really makes a difference. The graphics on my older iPod looks blurry and smudgy now.
These changes will be present in the next version, 1.3, that I am currently developing.
