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).

Note: This article has been updated – Detecting and Delivering Images to Retina Displays

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 + " &amp; Size : " + screen.width * window.devicePixelRatio);
	}else{
		alert( "Normal @ Pixel Ratio 1 &amp; 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
	}
?>

Tagged with:
 

24 Responses to Detecting the iPhone4 and Resolution with Javascript or PHP

  1. Mike says:

    Very helpful and informative. (and thorough!) Thanks.

  2. [...] have heard of media queries being used to target mobile devices (based on screen pixel width) or to target the iPhone 4′s Retina display, but you may not have known that you can also target screen [...]

  3. docilewalnut says:

    I was googling all over the place trying to find this exact solution. Great post, many thanks!

  4. DaveC says:

    Great post, thanks. Is there a way to detect device orientation using php? I’m guessing not but… it would be great for feeding variable dimensions to embedded videos/images.

    E.G.
    if (orientation == landscape){
    $width = 960;
    } else {
    $width = 640;
    }
    echo ”;

    Cheers
    Dave

  5. sexyprout says:

    You can detect iPhone 4 in PHP with Mobile/8A293

    • Ben Zemm says:

      No. That is the build number of software, nothing to do with hardware. My iPod 3G and iPhone 4 have the same Mobile/9A405 (same iOS 5.0.1).

  6. Ben Doran says:

    That’s actually a good point..!

  7. cyrex says:

    Very good article, thank you! :)

  8. evolutioneer says:

    @sexyprout, not true – my iPhone 3GS is coming up with that user agent. I will resort to Ben’s Javascript detection.

    Thank you Ben – you are a god among men!!

  9. Ben Doran says:

    @evolutioneer on further investigation the 8A293 tag is merely indicative of an 4.0 OS GM build, and not an iPhone 4 device.

  10. You can do it passing the device pixel ratio as a get parameter of the current page by simply redirecting when the javascript is displayed. then you don’t need cookies enabled, but still javascript.

    something like this :

    location.replace(location.href + ‘?device_pixel=’+ window.devicePixelRatio);

    this is the way i’ll do it

    • Ben Doran says:

      That’s a good point, I passed through the cookie, mainly due to the fact that I build sites with mod_rewrite urls, so using GET vars never usually help as it messes up these URLs.

      But you’re right of course, GET is much simpler, and I have used that method on a site before as well.

      Another option is to back-call the page with POST as well through Ajax, but that’s probably just silly :P

  11. Otto says:

    Thanks for this.

    I was desperately looking for a way to detect iPhone4 or 3….

    cheers

  12. Ben Doran says:

    It seems that iPhone 4S has fell prey to this same issue :( So this code will only tell you whether the connecting device is an iOS device with Retina Display or not, as of now there’s no discernible way of telling the difference between the devices in each category ie:

    Pixel Density of 1: iPhone 2G, iPhone 3G & iPhone 3GS
    Pixel Density of 2: iPhone 4 & iPhone 4S

  13. Great idea to detect with JavaScript and set a cookie, thanks for sharing!

  14. [...] only solution is to turn to something more powerful like JavaScript.Bdoran.co.uk has a quick example of how to detect the iPhone 4 with JavaScript or PHP that you should check [...]

  15. Quora says:

    What is the best method for adding 2x images to webpages that will be displayed on the new iPad with Retina graphics? Bonus question: What’s the best way to handle 2x sprites?…

    I saw a technique where you save this information to a cookie and then the server-side script would be able to serve the correct image. The problem with this is: it requires a reload to work We used it for a product, and it really worked. I personally …

  16. [...] fogom próbálni a window.devicePixelRatio tulajdonságot is, amit egy régi iPhone 4 Retina kijelzővel foglalkozó bejegyzésben találtam. Elsőre tisztább megoldásnak tűnik, mint a User Agent [...]

  17. [...] 不过可以试试Javascript,这儿有个例子。 [...]

  18. [...] мощному, к примеру. Например, JavaScript. Bdoran.co.uk приводят небольшой пример того, как обнаружить iPhone 4 при помощи JavaScript или [...]

  19. [...] мощному, к примеру. Например, JavaScript. Bdoran.co.uk приводят небольшой пример того, как обнаружить iPhone 4 при помощи JavaScript или [...]

  20. [...] my previous post Detecting the iPhone4 and Resolution with Javascript or PHP I highlighted one way of detecting retina displays (or high-density displays) using a quick but [...]

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>