iOS6 Tutorial: Delivering High-Resolution Content to the Mobile Web

Oct 05 2012

Now that high-resolution displays are becoming more and more common, some special consideration is required to make your web sites and apps continue to look their best. For this entry in the iOS 6 tutorial series I'm going to discuss some techniques for delivering high-resolution content to the web.

First of all let’s go over some context and examine why this is even a problem in the first place. Traditionally the resolution in displays has slowly increased over time and UI's appeared smaller or were redesigned to use the extra pixels. When Apple introduced the Retina display the jump forward in resolution was so large that for every pixel on a traditional display, there are four corresponding Retina pixels. Left alone with natural scaling normal UI elements would become impossibly small on Retina displays. To solve this Apple introduced a native software scale factor behind the scenes (2x for all current Retina displays) that scales UI elements' pixels to take up more of the device's pixels so that elements appear to be the same size.

How does this translate to the web? Pretty well, actually. Because CSS was designed with many different screens, scales, and devices in mind, CSS pixels (px) are relative. That is, 1px is not equal to 1 actual device pixel. In the past they have sometimes mapped 1-to-1 but they certainly don't have to. Because of this, designs and layouts won't break when scaled up from software (pinch) zooming or on higher resolution displays.

So, it's easy to see why this software scaling factor presents a problem for certain images. Browsers can do a pretty good job scaling things like text and vector assets, but for raster and bitmap images (.jpeg, .png, etc) there are only so many pixels available. To scale the image up, extra new pixels have to be interpolated. This is what causes images to become blurry when scaled, making your site look bad on a newer device. And while it's much less noticeable, scaling images down is not ideal either because some pixel data has to be thrown away. You should always try and have the number of device pixels be equal to the number of image pixels.

Scaled Image AppearanceScaled Image Appearance

So how do we accomplish perfect image scaling? Here are three techniques with various performance, simplicity, and cross-browser support tradeoffs. For each of these methods you will need image assets that are twice the size of the originals (there's no way around that one!).

CSS Sizing

The first technique is the simplest. It involves always using the high-resolution source image and scaling it down using the CSS properties width and height. For example:

<img src='vacation-highres.jpg'> // always use the 400x300 version
.img {
	width:  200;
	height: 150;
}

Now the image will look fine both normally and when scaled up on Retina displays. This approach is easy and cross-browser supported, but is pretty bad when it comes to performance. A non-Retina device still has to download and store in memory all of those high-res images, and will never even fully display them because that extra pixel data has to be thrown away to scale the image down.

Device Scale Querying

The next technique addresses the performance issue of always downloading the high-res image asset. There are a couple ways we can figure out the user's device scale factor and respond with the appropriate image - saving non-Retina devices the bandwidth and memory hit. One way to accomplish this is by using CSS 3's media queries with expressions. With media queries you can find the device's width:

@media screen and (device-width:320px) { // iPhone-size
	#container {
		...
	}
}

and also the scale factor of the device:

@media screen and (-webkit-device-pixel-ratio:1) { // non-retina (no scaling)
	#home {
		background-image: url(vacation.jpg); // normal image
	}
}

@media screen and (-webkit-min-device-pixel-ratio:2) { // retina+
	#home {
		background-image: url(vacation-highres.jpg); // large image
	}
}

These are -webkit vendor prefixes that are also available on Mozilla and Opera for a good level of cross browser support. Also notice the "min" in the second expression - this will match a device scale of 2 or above allowing for future device support. To save some code the above can be written as:

#home {
	background-image: url(vacation.jpg); // default normal image
	border-width: 5px 5px 5px 5px;
}

@media screen and (-webkit-min-device-pixel-ratio:2) { // overwrite for retina+
	#home {
		background-image: url(vacation-highres.jpg); // large image
	}
}

but don't forget that order matters in CSS - those two blocks in reverse order wouldn't work.

This same scale detection can also be done in JavaScript with

window.devicePixelRatio

if that's what you prefer. You do have to be careful using this method however as there's no auto-update if the screen size changes (e.g. window drag on two desktop monitors) like there is with media queries. To account for this you can evaluate media queries from JavaScript with an event listener:

This same scale detection can also be done in JavaScript with window.devicePixelRatio
if that's what you prefer. You do have to be careful using this method however as there's no auto-update if the screen size changes (e.g. window drag on two desktop monitors) like there is with media queries. To account for this you can evaluate media queries from JavaScript with an event listener:

window.matchMedia("(-webkit-device-pixel-ratio:1)").addListener(reload);

Device scale detection solves the performance issue of always downloading the large image, but it comes at a cost of less simplicity and more code. It is cross-browser supported with the -moz and -o vendor prefixes.

Webkit Image Sets

The final technique is certainly the cleanest but for the moment is only supported on Safari 6 and Mobile Safari on iOS6. Image set is a new CSS function developed by Apple that has been submitted to the CSS working group and is scheduled to be part of the images level 4 module. This new technique solves our issue very nicely:

#home {
	background-image: -webkit-image-set(url(vacation.jpg) 1x, url(vacation-hires.jpg) 2x);
}

If your site or app is only targeting iOS 6 this is a great option going forward.

In summary there are tradeoffs for each method listed above. Use the matrix below and decide which approach makes sense for your site. I would also recommended checking out the some of the great JavaScript libraries like Modernizr that help with implementing these techniques.

Hi-Res Display MatrixHi-Res Display Matrix

About the Author

Matt Kesler's picture

Matt Kesler is a CapTech Manager focused on mobile web technologies.

 

Disclaimer

The words and opinions expressed here are those of each article's respective author, and do not necessarily represent the views of CapTech Ventures.