Icons and splash screens for iOS web apps - retina displays also welcome / by Paulo Fierro

When creating web apps that are targeting iOS devices Apple provides a few hooks to allow things such as custom home-screen icons and splash screens for when people add them to their home screen. For icons you simply add the following to the <head> tag:

<link rel="apple-touch-icon" href="icon.png" />

If you want an icon without the default gloss you add -precomposed:

<link rel="apple-touch-icon-precomposed" href="icon.png" />

Different devices will need different sized images. The default of 57x57 is for older iOS devices, if you're targeting iPad you want 72x72 and if you're going to look good on the retina display on iPhone 4 you want 114x114. To tell the device which ones are present there is a sizes attribute where you can supply the size. So it looks like:

<link rel="apple-touch-icon-precomposed" sizes="72x72" href="/images/icon-ipad.png" />
<link rel="apple-touch-icon-precomposed" sizes="114x114" href="/images/icon-iphone4.png" />
<link rel="apple-touch-icon-precomposed" href="/images/icon-iphone.png" />

Notice how the last, default one does not have a sizes attribute - it doesn't need it. However, we found that it has to go last otherwise it may get overlooked on iOS3 devices.

Retina display splash screens

So far so good right? Well not so fast. Sadly Apple has not provided the same level of flexibility for splash screens. The sizes property does not work and there is no official documentation on how to provide a high-quality image for retina displays.

Disappointing but I suppose its currently an unsupported feature. Bleeding edge, cuts, etc.

Using media queries

Googling around you'll find lots of people asking this question but none of the solutions I tried worked. Some suggested using the aforementioned sizes property. Others suggest using media queries to target the right device. This does work for iPad and you can target a splash screen for landscape or portrait as follows:

<link rel="apple-touch-startup-image" href="/images/splash-ipad-landscape.png"  
media="screen and (min-device-width: 481px) and (max-device-width: 1024px) and (orientation:landscape)" />
<link rel="apple-touch-startup-image" href="/images/splash-ipad-portrait.png" media="screen and (min-device-width: 481px) and (max-device-width: 1024px) and (orientation:portrait)" />

The only strange thing is that the landscape splash image must be 748x1024 and you have to rotate the contents 90 degrees counter-clockwise. For portrait the dimensions are 768x1004.

So the logical thing would be to use the same sort of thing for targeting retina display. The regular splash image is 320x460 and the high-quality one is 640x920, so we were thinking we could target the right device using something like:

<link rel="apple-touch-startup-image" href="/images/splash-iphone.png" 
media="(max-device-width: 480px) and not (min-device-pixel-ratio: 2)" />
<link rel="apple-touch-startup-image" href="/images/splash-iphone4.png" media="(max-device-width: 480px) and (min-device-pixel-ratio: 2)" />

The first image is for devices that do not have a minimum device pixel ratio of 2. Sadly this does not work at all. So media queries do work for iPad detection and even iPad start orientation but not for iPhone 4. Frustrating.

PS: adding the -webkit prefix to min-device-pixel-ratio has no effect, I saw this a few places too.

So in an act of desperation we turned to JavaScript. We can check what type of device you are and if you have a retina display so we can try to inject an image for these devices. Select for spoiler alert -> this works.

JavaScript to the rescue

The logic is as follows:

  1. wait for when the document is ready
  2. check that the device is running iOS
  3. check that the device has a retina display
  4. check that the device is running iOS5 or above

The last point is important because an iPhone 4 running iOS4 does not support high-quality splash images (640x920) and will simply ignore any you provide. They don't display the low quality (320x460) one either, they just flat out refuse to display a splash image because you told it to do something it couldn't do. Its a bit touchy.

In any case we use jQuery to figure out when we have loaded, and general DOM magic allowing us to insert the high-resolution splash screen into the <head>, but only for iOS devices with a retina display running iOS5 or later.

function hasRetinaDisplay() {
	return (window.devicePixelRatio >= 2);
}
function isAppleDevice() {
	return (/iphone|ipod|ipad/gi).test(navigator.platform);
}
function iOSNewerThan(majorVersion) {
	if(isAppleDevice()) {
		// Check the version
		var pattern = /iPhone OS (.*) like Mac/;
		var result  = navigator.userAgent.match(pattern); // Returns "iPhone OS X_Y like Mac, X_Y"
		var version = result[1].split(''); // Returns X, Y
		var release = version[0];
		return (release >= majorVersion);
	}
	return false;
}

// When we're ready to go...
$(document).ready(function() { 
	if(hasRetinaDisplay() && iOSNewerThan(5)) { 
		var highResSplash = '<link rel="apple-touch-startup-image" href="/images/splash-iphone4.png" />'; 
		$('head').append(highResSplash); 
	}
});

So this is our CSS:

<link rel="apple-touch-startup-image" href="/images/splash-ipad-landscape.png"  
media="screen and (min-device-width: 481px) and (max-device-width: 1024px) and (orientation:landscape)" />

<link rel="apple-touch-startup-image" href="/images/splash-ipad-portrait.png" 
media="screen and (min-device-width: 481px) and (max-device-width: 1024px) and (orientation:portrait)" />

<!-- iPhone 4 devices running iOS5+ will get a high-res one via magic JS -->
<link rel="apple-touch-startup-image" href="/images/ios/splash-iphone.png" media="screen and (max-device-width: 320)" />

To sum up:

  • iPads will get the a splash screen for each orientation,
  • non-retina display iOS devices will get the lower quality image,
  • iPhone 4's running iOS4 will get the lower quality image (sadly), but
  • iPhone 4's running iOS5 or above will get a glorious, high-quality image (depending on your design skillz of course).

Hopefully Apple will sort this out in iOS5 and add support for the sizes attribute to the splash screen (or something cleverer). As it stands it appears to be very much an unsupported feature but, getting a high-res splash image on my phone? Totally worth it.