Menacing Cloud

Optimising for High Pixel Density Displays.

Recent mobile device releases have raised the bar in terms of display pixel density. The iPhone4 326PPI ‘Retina display’ is getting a lot of (deserved) attention in this respect.

This trend and the concurrent surge in tablet popularity means we're now designing for an extremely wide range of display specifications. High pixel density tablets can't be far away… (UPDATE. The new iPad did this as of March 2012).

In this article we'll discuss a maximum quality, minimum effort CSS and JavaScript approach to web sites/apps that cater for high density pixel displays.

The Pixel Conundrum

With the advent of high pixel density displays the pixel itself is now a relative unit.

According to the CSS 2.1 Specification:

Pixel units are relative to the resolution of the viewing device, i.e., most often a computer display. If the pixel density of the output device is very different from that of a typical computer display, the user agent should rescale pixel values.

So, a ‘CSS pixel’ indicates one point on the virtual pixel grid to which our CSS design aligns. This either directly matches the actual device pixel grid on which our content is rendered or it is intelligently scaled.

This has led to the definition of a ‘Density-independent pixel (dip)’. (Android Developers)

A virtual pixel unit that applications can use in defining their UI, to express layout dimensions or position in a density-independent way.

iPhone4 was not the first to employ virtual pixels although other implementations often had less convenient scaling factors. 1 virtual pixel could equal 1.5 physical pixels and so on.

A detailed summary of the ‘Pixel is not a pixel’ situation is available on quirksmode.

Fixed vs. Fluid Layouts

Like it or not, fixed layouts now exhibit fluid behaviour on displays that employ density-independent pixels.

The fixed vs. fluid layout argument has been rendered irrelevant.

Fixed layouts will continue to work acceptably on iPhone and other mobile web-enabled devices. The touch interaction method that iOS, Android etc. employ is a great solution. The virtual pixel scaling algorithm does a great job, the end result being the quality that iPhone4 exemplifies.

However, when targeting mobile devices via CSS Media Queries the virtual pixel situation rapidly gets confusing. Fixed layouts were popular because exact ‘pixel perfect’ control was simple, now it's simply not.

What happens if future high pixel density displays require 2.5x scaling or even pixel tripling? How much relative pixel math with awkward ratios can you endure?

Take the plunge, move to simple, logical units (em's, percentages etc.).

Consider Hybrid/Adaptive CSS

This technique enables all the freedom in the world to tweak for specific devices.

  • Start with a basic fluid CSS design.
  • Tweak for specific ‘device-width’ ranges with Media Queries.
  • Even better, use ‘width’ queries for even further flexibility and easy prototyping.
  • Tweak further with ‘device-pixel-ratio’ queries.

You'd be safe in the knowledge that the fallback fluid layout would be presentable since it would scale smoothly across multiple devices due to it's independence from pixel ratio.

A great implementation example is the Hicksdesign website.

Text Rendering

Typography is an underrated area of mobile web design. Great text makes a big difference on small displays.

Mobile devices also allow for extreme enlargement (via zoom). This is where high pixel density displays really shine. Text looks extremely smooth at all zoom levels.

The ‘text-rendering’ CSS options, specifically ‘optimizeLegibility’ are worth enabling on high pixel density screens.

Enabling it yields improved support for kerning pairs and ligatures. They look great on iPhone4!

/* Heading kerning pairs and ligatures */
h1, h2, h3 { text-rendering: optimizeLegibility; }

It degrades gracefully to standard text rendering if not supported. Demo.

Enhanced Typography

Techniques like @font-face are perfect for multi-device typography.

  • Headings scale with embedded fonts.
  • The commonly used alternative, header images, do not scale attractively.

Combined with carefully chosen fonts, CSS text shadowing and the improved text-rendering declaration, we have some great options for fantastic high resolution typography.

Targeting High Pixel Density Displays

The device-pixel-ratio Media Query can be used to target style for high pixel density displays.

<!-- High pixel density displays -->
<link rel='stylesheet' href='highRes.css' media='only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min-device-pixel-ratio: 2)' />

Note that for the moment vendor prefixes are required.

Opera requires the device pixel ratio as a fraction and the -moz ‘prefix’ does not operate as one would expect.

-moz-min-device-pixel-ratio // NOT this. min--moz-device-pixel-ratio // Yes, makes no sense, but this is it.

The above Media Query is discussed at MiniApps – Targeting iPhone4 using CSS Media Queries.

Media Queries continue to provide a strong starting point for all CSS based device-pixel-ratio and device-width optimisation decisions.

Device pixel ratio can also be queried in JavaScript.

var dpr = 1; if(window.devicePixelRatio !== undefined) dpr = window.devicePixelRatio;

Higher Image Quality

The most prominent trick to come out of pixel ratio Media Queries is high-resolution background image substitution.

For example, a website header could vary quality in line with the pixel density of the display it is rendered on.

  • Separate images are created for each device pixel ratio we wish to support (e.g. 1x, 1.5x, 2x).
  • The default (normal-res) background header is specified via CSS.
  • For high pixel density displays, the high-res image is substituted in.
  • The image background-size is scaled by the inverse of the device pixel ratio.
  • In the case of the iPhone4 the image is twice the resolution, scaled to 50% in the CSS.

This maintains the correct relative size on screen, but results in noticeably improved image definition on screens that support it.

Assuming a desired 100 by 100px (virtual pixels!) image size, the saved image resolutions would be as follows,

  • 1x: 100px
  • 1.5x: 150px
  • 2x: 200px
/* Pixel ratio of 1. Background size is 100% (of a 100px image) */ #header { background: url(header.png); } /* Pixel ratio of 1.5. Background-size is 1/1.5 = 66.67% (of a 150px image) */ @media only screen and (-moz-min-device-pixel-ratio: 1.5), only screen and (-o-min-device-pixel-ratio: 3/2), only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-device-pixel-ratio: 1.5) { #header { background: url(headerRatio1_5.png); background-size: 66.67%; } } /* Pixel ratio of 2. Background-size is 1/2 = 50% (of a 200px image) */ @media only screen and (-moz-min-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min-device-pixel-ratio: 2) { #header { background: url(headerRatio2.png); background-size: 50%; } }

There is a problem with this. The device pixel ratio is not always a neat ‘2’ as with the iPhone4. How many images are you willing to produce? Already, just with 1x, 1.5x and 2x, that's three images! This won't get any easier.

The solution? Create one large (2x resolution) image and then scale down by 50% (in-browser) via CSS for all pixel density displays.

Devices without a perfect ‘2’ pixel ratio will still produce better results than a low-resolution image, for far less work.

Browsers (including mobile browsers) have great scaling mechanisms nowadays so the resulting image quality will be good across all devices.

Yes, this does mean greater bandwidth required. Looks vs. performance would require consideration.

Mobile stylesheets shouldn't be using many images anyway, so perhaps this is just a proof-of-concept technique with little real world significance.

Remember that a lot of people on iPhone4s are also now paying for their data!

If pixel ratios exceed 2 in future then consider SVG or a similar technology. Besides, surely 2x is near the maximum? 326ppi is the ‘Retina Display’ after all :-p

‘That's because the Retina display's pixel density is so high, your eye is unable to distinguish individual pixels.’ - Apple Inc.

Inline Images

We've taken care of images specified with CSS, but what about standard <img> tags?

If you're happy serving up high-resolution images, then we can use a similar scaling technique. This could be accomplished with the following JavaScript snippet (using jQuery for brevity).

Only enable pixel ratio related JavaScript where necessary. This can easily be done with JavaScript pixel ratio detection. We assume a 1:1 pixel ratio if the browser doesn't support it.

// Query the device pixel ratio. //------------------------------- function getDevicePixelRatio() { if(window.devicePixelRatio === undefined) return 1; // No pixel ratio available. Assume 1:1. return window.devicePixelRatio; } // Process all document images //----------------------------- function processImages() { if(getDevicePixelRatio() > 1) { var images = $('img'); // Scale each image's width to 50%. Height will follow. for(var i = 0; i < images.length; i++) { images.eq(i).width(images.eq(i).width() / 2); } } }

All document <img> elements are automatically resized on high pixel density screens. Normal 1:1 screens can either leave the image unscaled, or force the scale of all images via a separate function (included in the source). Your call.

There is a better method. Tag images that are to be high-resolution with a class.

<img class='highRes' />

Then target <img> elements tagged with this class with the JavaScript scaling technique.

// Only process tagged document images //------------------------------------- function processTaggedImages() { if(getDevicePixelRatio() > 1) { var images = $('img.highRes'); // Only images with class 'highRes' // Scale each image's width to 50%. Height will follow. for(var i = 0; i < images.length; i++) { images.eq(i).width(images.eq(i).width() / 2); } } }

Now for a demonstration. One image is class tagged as 'highRes'. Note, on 1:1 pixel ratio displays, these images will be the same size.

For the full details of how this works, check out the source code.

If you decide to make all your images high resolution and scale by 50% you could have a lot of wasted bandwidth for viewers on 1:1 pixel ratio displays. You do have some flashy waste reducing options, depending mainly on how much work you are prepared to put in.

  • Simply link to the same image, which would display it without scaling.
  • Display it in a lightbox when clicked.

CSS targeted at mobile devices often scales images anyway. This usually means a single column with images occupying 100% of the device width. If this is your mobile design strategy, stick with it. Just be aware that you can now get higher image quality if required.

There have been suggestions concerning automatic fetching of high resolution images. These techniques do have potential, but until the performance implications (request numbers, 404s etc.) are taken care of then this method is not feasible.

If this could somehow be done on the server side, then it could be very popular. It would also have to include automatic image scaling, so that web designers aren't manually creating many versions of the same image.

Use CSS Enhancements

  • Gradients
  • Rounded corners
  • Text shadows, box shadows
  • And so on…

Use the CSS tools at your disposal. They're resolution independent and bandwidth friendly!

Parting Thoughts

You don't need any of the aforementioned optimisations, they're optional!

From device pixel ratios and scaling to the zoom interaction method popularised by the iPhone, tweaks for high pixel density displays are simply a nice touch on what is becoming a very solid mobile web browsing experience.

Thanks for reading.

Comments

Comments, suggestions or feedback via Optic Swerve on Twitter please.

Follow the author on Twitter.

ProtoFluid. ‘Effortless responsive web design testing’.

Previous Articles

Canvas Generated Icons. Read more.

Targeting Windows 8 Snap Mode. Read more.

CSS @viewport rule or viewport meta tag? Read more.

The Responsive Viewport. Missing piece of the responsive web design puzzle? Read more.

Getting the Viewport Scale.
Read more.

Hiding the iPhone Address Bar.
Read more.

Orientation Correct Screen Width.
Read more.

iPhone Title Modification.
Read more.

Optimising for High Pixel Density Displays.
Read more.

CSS3 Media Query Prototyping With ProtoFluid.
Read more.

AJAX Kill Switch. Version 2.
Read more.

URI Processing With JavaScript.
Read more.

Source Code

All source code is provided for free.

A standard disclaimer of warranty and limitation of liability applies.