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.

Comment Pages

There are 8 Comments to "Retina display and web development"

  • Robert says:

    Excellent information!

    I don’t have an iPhone/iPod 4 to test with, but at such a point that I get one, this will be useful information for any experimenting I do :)

    Thanks for sharing :)

  • admin says:

    Thanks,

    It will also be interesting to see what for example Android does when they move beyond 800×480, and on devices with very high dpi, if they will choose a similar approach as in iOS.

    I am a big fan of World of Solitaire btw! great work :-)

  • Andreas says:

    thanks a LOT for sharing.
    it took me days trying to solve that issue using the CSS/canvas.scale … which turned out to be an improper solution for my approach . . .

    btw – do you have any ideas on how to deal with the “web app startup image” issue on retina display equipped devices?

  • admin says:

    Glad to be of help :-)

    As for the startup image, I just added a 960×640 Default@2x.png image to xCode as a resource, and it was automatically selected and displayed correctly on startup.

  • Andreas says:

    unfortunately that’s only working for native apps, my problem is with a pure web app – while the precalculated initial/min./max.-scale meta tag works for anything in a safari frame (web page, web clip, native container app) . . .
    i have to admit i also desperately tried appending „@2x“ to the startup-image meta tag’s content ;) – of course without any luck. so it seems to me, apple has simply forgotten improving that tag’s functionality towards the retina display although they managed to handle the touch-icon tag on each display resolution properly.

  • admin says:

    Ah, ok the apple-touch-startup-image. Looks like its not possible currently. There was some posts about it on the iOS development forum, and noone has the solution. I think they forgot too. Since there is a check for exactly 320×460 that check is probably still in place.

  • Horst says:

    Many thanks for this post. I have an phonegap app wich has one chart, which shall be displayed in full resolution. The rest is text only.
    So i use your solution. On Android i have to change the device-width to screen.width. This works fine on 2.2 (older versions have some strange canvas errors with images).
    But on iOS screen.width is always 320. So i have to use screen.width*window.devicePixelRatio to get real size. For changing the resolution i change the scale, like you do.

    But it doesent work always on iOS. Sometimes the old low resolution stays. I have no idea when it works and when not.

  • Horst says:

    I have found it. When the virtual keyboard was shown, the viewport can’t changed anymore.