web-engineer labs, a think-tank of ideas, experiments and other stuff

Design for retina type displays

01-Nov-2012

This re-styled input control when viewed on a retina display showed a pixel gap, a result of the scaling up of the sprite sheet behind the control.

Whilst working on a project targeting touch screen devices, everything was going well, until we obtained the "new" iPad for testing. Graphics looked fuzzy, minor mistakes in layout resulted in very noticeable gaps; the stunning display had made the application look positively less than average. This was less than ideal and I quickly realised that this too was the reason for a number of display quirks on the iphone, whose screen being smaller and even higher definition (at 326dpi vs the 264dpi) made these tricky to spot.

This article focuses on getting the most from a high pixel density display, I start by exploring some the basic constructs and explore the benefits. Our workflow here frequently involves using Fireworks some specific advice is also given, much of this may still be relevant to other graphics packages.

Pixels are as points are to print

Points relate to real world size in print, therefore we could be forgiven for thinking that we have the constructs defined to deal with resolution issue by moving to points on screen. This falls apart if you take a handful of different devices and browsers and put this to the test, you soon find that points do not guarantee that the type is physically the same size. Points belong to our print stylesheets and that is where they should stay.

Design for screen is a different ballpark, the CSS 2.1 specification makes it clear how this should be handled and helps to give some clarity to the standard methodology.

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.

The point is a print unit, in which your normally designing for a specific format or page size. On screen you do not have the luxury of knowing the scale of the screen or the viewing distance from the device – this is what pixel density should solve since manufacturers will set this according to what will give the user the best view of the content. An iPhone 4 for instance has a higher pixel density than the "new iPad" when using the devices it is clear that this is entirely right for the use of the devices. On the phone you compromised by size and your eyes tend to be closer at the device than perhaps they would be when using an iPad which is more magazine like in format, i.e. something you can sit down and relax with.

This is a non-retina view demonstrating a potential loss of detail.

Device pixel ration is a simple solution that enables devices to support existing content from otherwise shrinking away. By effectively making the pixel to a relative unit of measurement this means the technical advancement of the device will not alter the basic browsing experience. This leaves us as developers with some new technical considerations.

There are some simple rules that should be followed to ensure the best possible user experience, these are –

Avoid use of CookiesAside from the usage policy update the main downside is that every http request will have your cookie sent with it, this also requires server side processing to re-route the request, a little messy and there will be a speed penalty mainly in the processing of the HTTP request.

On media queriesThese are an excellent way to feed the correct assets to your device, most browsers support them but unfortunately in the Explorer camp only version 9 or later supports them.

Consider sizeThe normal rules should still apply – some large images or photographic assets may not warrant the extra bandwidth or look a great deal better! Avoid making the situation worse by forcing both versions to be downloaded or just using the larger image as this is wasteful on resources and will give devices with less memory trouble.

Volume levelIf a high definition display is detected consider giving the user an option of switching to low quality. The device may be on a slow connection, download speed could make your design unusable.

Be progressiveApproaches that use JavaScript can be made to work well, it is important however to consider taking basic controls with no styling and enhancing them to suit the viewing device, preventing serving extra assets and tailoring the controls to suit.

Handling of type

As pixels are a relative measurement and considering that your type may actually be in proportion to the size of the images on the page, we should stick to pixels throughout. Pixel density is set by the manufacturer of the device to reflect an appropriate scale for content to be displayed, your type will look at it’s best when you stick to pixels. If the viewer wants larger text the browser or the operating system will have the option to scale the whole page up, not just the type.

You can also further enhance the quality of the type by enabling kerning pairs and ligatures, these look great with the extra pixels available on high density displays. The following css rule will enhance the appearance of type and is supported by most devices –

A comparison of the same line of text, one with kerning and ligatures enabled

<css/>

h1,h2,h3{
text-rendering: optimizeLegibility;
}

CSS sprites and media queries

What would normally live in CSS is relatively simple to update supplement with a sheet to list the replacement urls to the high definition assets add the background size attribute to your containers. Only the correct assets will hit the correct devices. You can target the high definition displays by supplementing your site with a separate stylesheet via a media query as follows, for clarity I’ve wrapped the lines, this should in practice be one line. This deals with prefixes for mozilla, opera, webkit and the w3c standard.

<xml/>

<linkrel="stylesheet"href="/css/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)"/>

The following examples shows the difference between the regular CSS sprite rule and a high definition one.

The same rule in the highres.css, this overrides the sprite file with one suffixed "-x2" it’s good to set out and stick to a naming convention that works for you. Provided that the sprite is laid out the same way, proportionately scaled up this will always work. Note – the size units are as per the sprite at pixel density 1.

IE9 does understand media queries, however IE8 will load this sheet regardless, the "@media" line prevents the rules from being parsed by IE8. Earlier versions of IE will apply the rules regardless and end up downloading the assets anyway. Whilst this results in extra bandwidth for those legacy browsers this may be an acceptable trade off. Alternatively you could use javascript to push the correct stylesheet into the head.

Depending on the pixel ratio being targeted (most likely 2) you can then simply upscale your graphics. In the above example the sprite would actually be 20×20 pixels in size for a target density of 2.

You could use 100% as the size dimension, however this will only work if your using a single graphic as opposed to a single sprite. Since specifying the pixel dimensions works in both sprite and single graphics it’s most likely easier to stick to specifying the pixels every time.

The single pixel border…

One of the possible drawbacks of pixel density is that the concept of a single pixel is altered. As much as this is a strength it can be a pain when we get to border widths.

If you specify a border of 1px on a screen with a density of 2 you will end up with a 2 pixel border, so what happens if you were trying to use a finer line? Part pixel units don’t work, your border will vanish. This can be achieved by using a sprite sheet with the pixels exactly how you want them, the regular sized sprite can give the illusion of a finer line by using a lighter (or darker) colour to make your lines look thinner.

Icons were re-worked in fireworks using vectors within symbols. This enables us to use the same graphics at different scales for the purpose of exporting both retina and standard sprite sheets.

Generating your assets using Fireworks CS6.

Fireworks is a great tool for generating sprite-sheets. The process of up-scaling graphics in Fireworks is greatly enhanced by using vectors. A good technique for generating sprite sheets is to create your assets as a symbols then simply duplicate and scale down for the purpose of exporting. This ensures you only have to manage one set of graphics saving a great deal of time.

CS6 adds the new save as sprite sheet function, though useful for building the 1:1 sheet, it doesn’t appear to support higher pixel densities. This is feature is still helpful since it is relatively simple to tweak the output for your high definition sheet. The following css rules are a snippet from the file which was generated when exporting the smaller icon set shown right.

I simply used a separate single slice for may double scale version, and added overrides in the highrez.css which was included for those devices supporting it.

Note your exported sprite sheet is likely to have a different arrangement to that within your source document. Check your exported sprite sheet to see how the sheet has been arranged. If this is different you can import the exported sprite sheet on a fresh page for use as a guide. By scaling this sheet up by the desired pixel density you can then lay out your high definition symbols knowing that the placement will be correct.

Paste the css in the box below and hit convert to create a high res. version, the only thing you may need to edit is the high res. filename, the convertor simply adds "-x2" to the filename of the high res. sprite-sheet.

What about regular images?

There is no simple way to determine whether or not to serve a larger image when using the standard IMG tag that does not involve adding cookies, running javascript or generating extra load to download your page. Regular image tags can be used as usual, specifying the single pixel size of the image works the same way as our css rules do. If the pixel density is double and your image is twice the size it would look correct on a double density display. Knowing whether the device would support that quality of image is tricky, the least evil approach is to use JavaScript. This way a simple script block can be used to check the available pixel density and write out the correct image tag. You could, if your concerned about the tiny number without JavaScript support, use a no-script fallback.

Conclusion

I have found working with a retina product quite an eye opener, with some forethought and by sticking to the basic principles you can get fantastic results. I’m sure as speeds have increased and devices become more prolific having your site looking it’s best can only help to increase adoption.

To pull together our findings we have released the Retinize project over on github which contains some useful scripts and a demonstration. This simple solution makes it easy to support Retina graphics and plays nicely with all major browsers, degrading gracefully on those that lack support. The project solves the following –

A simple way to manage style sheet inclusion based on device capability.