The new iPhone4′s retina display presents a new (although nice to have) problem for web developers. How to detect and deliver content to a 300dpi screen. There’s a wealth of information about how retina display works, so I won’t bore you with the specifics, Apple basically put twice as many pixels in the same width and height of the original screen. This means that the resolution is actually 960×640, although it reports to browsers and javascript that it has a screen dimension of 480×320, which is the resolution of the original iPhone (more on this later).

So the iPhone’s retina display is slightly different from a hi-res 960×640 display, it’s actually a 480×320 display with twice as many pixels (crazy huh?). The thinking goes a little like this, the device has a 480×320 “virtual pixels” so when measuring the device using javascript or in code it returns these pixels, however each of these pixels is represented by 2 actual screen pixels on the new device. This enables old web code to be compatible with both devices.
After googling for a long time on how to deliver content to the new device, the best I found was Aral Balkan’s excellent article on the higher DPI and how to use it to deliver higher DPI content (http://aralbalkan.com/3331).
However he talks about using css media queries as outlined by Apple in it’s webkit recommendations:
<link
rel="stylesheet"
type="text/css"
href="/css/retina.css"
media="only screen and (-webkit-min-device-pixel-ratio: 2)"
/>
However if I want to mealy deliver a single image in the normal way using an image tag, I know I can do it through CSS, using SVG and such, but what if I would like to just do a straight detection of the iPhone4, and deliver dynamic content myself. I’d have to somehow detect that the device connecting was a iPhone4 or at least a hi-res device, using a new hi-pixel display. You’d think I’d be able to use the javascript screen or viewport object. However both of these return the “virtual pixel” dimensions not the new ones.
I think Thomas Mair describes the new display in a nice way, when describing why we need custom CSS:
The reason is, that because every pixel is half the visual size, you may have to double the values of many CSS properties. For example text-shadow: 0 1px 0 #fff; which is like a half visual pixel on the iPhone 4. So to make a one-pixel line (better: looks like a one-pixel line) you have to write 2px. This preserves the visual size and adds a very smooth appearance – like we expect it from a Retina display. It also makes huge improvements for layouts on the iPhone 4 possible.
In short the only way I’ve found of getting the actual screen dimensions of the new device is by using the pretty well hidden “window.devicePixelRatio” property so :
<script type="text/javascript">
if( window.devicePixelRatio >= 2 ){
alert( "Hi Res @ Pixel Ratio : " + window.devicePixelRatio + " & Size : " + screen.width * window.devicePixelRatio);
}else{
alert( "Normal @ Pixel Ratio 1 & Size : " + screen.width + "+" + screen.width);
}
</script>
Obviously if you were doing a serious app, you would detect also detect check if the property window.devicePixelRatio exists before doing any computation on it.
But what about PHP, or server side technologies. Well this is were Apple make there second slightly odd choice. When detecting any mobile device from a server most people will use the UserAgent string, to detect the device, and then deliver content. However the iPhone’s user agent is based on the OS and not the device, this may sound like it makes sense, but it bucks a trend made by most other companies who put the model as well as the OS into their device agents. The iPhone 4′s user-agent on iOS4 is exactly the same as the iPhone3GS running the same OS.
iPhone4 & 3GS –
Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_0 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8A293 Safari/6531.22.7
This means the iPhone4 is completely undetectable by PHP and other server side technologies, as they have no way of detecting things like screen width. The only solution is to use Javascript to add the devicePixelRatio to a cookie, this can then be picked up by PHP and used, it’s not clean but until Apple sorts out it’s user-agents, it’s the only way to detect it in PHP.
<?php
if( isset($_COOKIE["pixel_ratio"]) ){
$pixel_ratio = $_COOKIE["pixel_ratio"];
if( $pixel_ratio >= 2 ){
echo "Is HiRes Device";
}else{
echo "Is NormalRes Device";
}
}else{
?>
<script language="javascript">
writeCookie();
function writeCookie()
{
the_cookie = document.cookie;
if( the_cookie ){
if( window.devicePixelRatio >= 2 ){
the_cookie = "pixel_ratio="+window.devicePixelRatio+";"+the_cookie;
document.cookie = the_cookie;
location = '<?=$_SERVER['PHP_SELF']?>';
}
}
}
</script>
<?php
}
?>