
The latest iPad has a 2,048 x 1,536 pixel resolution at 264 pixels-per-inch (PPI) screen, the iPhone 4 and iPhone 4S have greater pixel density: 960 x 640 pixel resolution at 326 PPI. It isn’t just Apple’s devices that can be considered high-resolution, even if they don’t boast marketing terms like Retina display.
The HTC One X uses a 4.7-inch display, with 312 PPI for example; and even Sony’s latest handheld gaming device, the PlayStation Vita, has a 220 PPI screen. We now have Apple’s Retina display MacBook Pros too, at 220 PPI. It’s easy to see where this is going; pretty soon high-resolution/PPI displays will be the norm on all devices that access the web. The pickle at present is that while text looks beautiful on these devices, web images usually don’t. As high-resolution devices often have two dots per CSS pixel, the result is that images end up looking blurry.
Thankfully, there are a number of things we can do to address this issue. Let’s take a look at how CSS3 media queries and icon fonts can ease our pain, and then deal with the obvious elephant in the room; delivering alternate images in markup.
CSS minimum-resolution
CSS3 media queries can be used to target high-resolution/PPI screens; we can use them to serve different background images depending upon the pixel density of the device. By now you are no doubt familiar with the media query syntax. Let’s suppose we want to show two images, one for standard screens and one for high-PPI devices. We can go ahead and use the old min-resolution property:
001 @media (min-resolution: 96dpi) {
002 /* rules here would apply to a normal screens */
003 }
004 @media (min-resolution: 192dpi) {
005 /* rules here would only apply to high-
resolution screens */
006 }
About those iDevices
Sadly WebKit (iOS, Android, Safari, Chrome and others) hasn’t implemented min-resolution, and so we need to use WebKit’s own property. It uses a simpler system where the value represents the pixel density of the device. A ‘normal’ screen will have a pixel ratio of one. An iPhone 4 or similar, on the other hand, could be targeted like this:
001 @media (-webkit-min-device-pixel-ratio: 2)
002 {
003 /* Webkit high-resolution specific rules
here */ }
Other WebKit devices
While the WebKit prefixed rule also targets Android devices, many Android handsets (although still enjoying high-resolution screens), don’t have quite the same pixel density as something like an iPhone 4, 4S or new iPad – and none have anything near Retina display. Therefore, you may want to lower the threshold to include more devices.
001 @media (-webkit-min-device-pixel-ratio:
1.5) {
002 /* lower threshold rules here */ v
003 }
Mozilla is different
Another vendor, another expression! Mozilla uses a comparatively odd syntax. If you want to target high-resolution/PPI devices that might be using a Mozilla based browser such as Firefox, pay special attention as the minimum part of the expression is written first, followed by a double-hyphen:
001 @media (min--moz-device-pixel-ratio: 2) {
002 /* Mozilla rules here */
003 }
Opera syntax
Unbelievably, Opera uses a different syntax again. While similar in syntax to WebKit’s version (albeit with an -o- prefix as opposed to -webkit-), Opera has opted for a ratio representation of the pixel density. For example instead of writing 2 as the value (as you would with WebKit), it must be presented as 2/1.
001 @media (-o-min-device-pixel-ratio: 2/1) {
002 /* Opera rules here */
003 }
The W3C way?
Owing to the prevalence of the -webkit- prefixed version of this media query, you may be forgiven for assuming that the W3C would follow suit, declaring an unprefixed version of that syntax as the global web standard. However, as minimum-resolution already existed, they have not done this and have instead opted to add a new unit of measure, dots per pixel, written as dppx in CSS. Below is what the syntax is likely to be styled as in the future:
001 @media (min-resolution: 2dppx) {
002 /* rules here will apply to high
resolution media in the future */
003 {
Full vendor stack
Let’s go right ahead and put all these previous vendor versions together with the likely W3C implementation (dppx), into one media expression that we can use to bulletproof this technique whenever we implement it. The user-agent (whichever browser you are using) will happily ignore any expressions that don’t apply and render the one most relevant, ensuring cross-browser functionality.
001 @media (min-resolution: 192dpi), (-webkit-
min-device-pixel-ratio: 2), (min--moz-device-
pixel-ratio: 2), (-o-min-device-pixel-ratio:
2/1), (min-device-pixel-ratio: 2), (min-
resolution: 2dppx) {
002 /* High Resolution styles go here */
003 }
A use case
Let’s suppose we wanted two versions of a site logo, one for high-resolution screens and another for everything else. Using our full vendor stack from the previous step to achieve parity across browsers, here is an example of how we could set one image for normal screens and another for high pixel-density displays:
001 .logo {
002 background-image: url('../img/logo.
png');
003 }
004 @media (min-resolution: 192dpi), (-webkit-
min-device-pixel-ratio: 2), (min--moz-device-
pixel-ratio: 2), (-o-min-device-pixel-ratio:
2/1), (min-device-pixel-ratio: 2), (min-
resolution: 2dppx) {
005 .logo {
006 background-image: url('logo@2x.png');
007 }
008 }
Making it fit
While that will display the correct image, if we set a high-resolution background image as our logo, and the logo div it sits in is smaller in pixel size than the image, ordinarily it will overflow the container. Thankfully, there is a CSS3 property that can solve our issues. We can use the background-size property with a px value or contain value to make it fit:
001 @media (min-resolution: 192dpi), (-webkit-
min-device-pixel-ratio: 2), (min--moz-device-
pixel-ratio: 2), (-o-min-device-pixel-ratio:
2/1), (min-device-pixel-ratio: 2), (min-
resolution: 2dppx) {
002 .logo {
003 background-image: url('logo@2x.png');
004 background-size: contain;
005 }
006 }
Background-size options
The background-size property can also take numerical values. Using pixels for size can be useful if you want your images to stay a set size within a fluid container. The width is given first, then height. If no height is given, auto is assumed for the height. A percentage can also be used and this will render the image as a percentage relative to the container.
001 .background-size-dimensions {
002 background-size: 300px 300px;
003 }
Naming conventions
You’ll notice in step 9 that the high-resolution logo file name is the same as the standard resolution targeted one, except it has been suffixed with ‘@2x’ before the file extension. This is a naming convention used by Apple when targeting their Retina displays. It’s actually not necessary, but many pre-existing JavaScript solutions use this convention, so it may be something that is worth adopting.
001 .standard {
002 background-image: url(‘image.png’);
003 }
004 .high-resolution {
005 background-image: url(‘image@2x.png’);
006 }
Icon fonts
If you want to provide scalable icons for a design, there is a better option than images: icon fonts. There are a growing number of icon fonts available, and they can be included in a design using the @font-face rule. You’ll need a version of your icon font in WOFF, SVG, EOT and TrueType to cover all browsers. Then use the @font-face rule to include it.
001 @font-face {
002 font-family: ‘hr’;
003 src: url(‘fonts/hr.eot’);
004 src: url(‘fonts/hr.eot?#iefix’)
Setting up defaults
In this example we are using fonts from IcoMoon (which can be found here: keyamoon.com/icomoon/#toHome), which are mapped to characters. Therefore, we can add them by adding a particular class to the icons needed in the markup. First of all, we’ll define styles that will be particular to all the icons. This will cover us wherever the classes are ordered among others.
001 [class^=”icon-”]:before, [class*=” icon-
”]:before {
002 font-family: ‘hr’;
003 font-style: normal;
Adding with class
We can now add the relevant icon wherever we want by adding the relevant class. The icon is inserted before the element it is added to. If you want the icon to appear afterwards simply amend the pseudo selector from before to after.
001 .icon-chrome:before {
002 content: “21”;
003 }
004 .icon-firefox:before {
005 content: “22”;
006 }
007 .icon-opera:before {
008 content: “23”;
009 }
010 .icon-globe:before {
011 content: “24”;
012 }
013 .icon-check-alt:before {
014 content: “25”;
015 }
Adding icons inline
Adding the icons inline without a pseudo selector is not a good idea semantically, as the content is meaningless. If you wish to, remember to use character entities for each number. Otherwise the number will appear as is. Here, we are adding all the icons in a row.
001 /* CSS */
002 .icon-insert {
003 font-family: ‘hr’;
004 font-style: normal;
005 speak: none;
006 font-size: 5em;
007 }
008 <!-HTML -->
009 <p class=”icon-
insert”>! " #
$ %</p>
Inserting as data attribute
You can also use data attributes to insert icon fonts. This lets you keep the icons out of the actual page content itself. Remember that any attribute beginning ‘data-‘ in HTML5 is perfectly valid code, so it isn’t going to sour the markup for validators. Insert the icons in the markup in the same way as the previous step: using character entities.
001 /* CSS */
002 [data-icon]:before {
003 font-family: ‘hr’;
004 content: attr(data-
icon);
005 speak: none;
006 font-size: 5em;
007 }
Font flexibility
By using fonts, the icons will scale to any resolution and can have colour, text-shadows and even experimental ‘-webkit-mask-image’ values (for WebKit browsers) added. What’s more, compared with images, the file size is tiny. For the five icons used here, the largest font that would be served is just eight KB (before gzip).
001 [class^=”icon-”]:before, [class*=”icon-”]:before {
002 font-family: ‘hr’;
003 font-style: normal;
004 speak: none;
005 font-size: 5em;
006 color: green;
007 -webkit-mask-image:-webkit-linear-gradient(white
,rgba(0,0,0,0.7));
008 text-shadow:0 -1px black;
009 }
Using Picturefill
There is no proper way to add alternate high-resolution images such as photos in markup yet. One solution is to use Picturefill, a JavaScript solution that follows a markup pattern similar to the HTML5 <video> tag. After adding the Picturefill JS file within the markup, alternate images can be specified using media query style expressions. Note the slightly different syntax present for the media query.
001 <div data-picture data-alt=”An image, whose source changes depending upon the media query style expressions”> 002 <div data-src=”normal.jpg”></div> 003 <div data-src=”high-resolution. jpg” data-media=”(min-resolution: 192dpi),(-webkit-min-device-pixel- ratio: 2),(min--moz-device-pixel- ratio: 2),(-o-min-device-pixel-ratio: 2/1),(min-device-pixel-ratio: 2),(min- resolution: 2dppx)”></div> 004 <!-- Fallback content for non-JS browsers. Same img src as the initial, unqualified source element. --> 005 <noscript><img src=”normal.jpg” alt=”An image, whose source changes depending upon the media query style expressions”></noscript> 006 </div>
Adaptive images
A great tool for delivering images on a responsive website can also be used to deliver high-resolution images where needed. Head over to adaptive-images.com and after installing (you are going to need access to your server’s .htaccess file), alter the standard line of JavaScript used, to:
001 < script>document. cookie=’resolution=’+Math.max(screen. width,screen.height)+(“devicePixelRatio” in window ? “,”+devicePixelRatio : “,1”)+’; path=/’;< /script>
Uploading high-resolution files
When using Adaptive Images for high-resolution images, you’ll probably want to limit which images are processed by it. You can limit this by altering the .htaccess file. For example, if we didn’t want Adaptive Images to resize images inside a folder called no-thanks (folder addresses are root relative) we could add a line that looks like this:
001 RewriteCond %{REQUEST_URI} !no-thanks
Fit and forget
One great thing about Adaptive Images is it works by re-using existing images where possible for high-resolution screens. For example, if viewing on an iPhone 4 in portrait, Adaptive Images will multiply the CSS pixel-width of the device (320px) by the pixel density reported (2) and use that value (640px) to check and use an image matching that size where possible.
SVG files?
If you have vector images, another option is to consider exporting them SVG(Z) files. Like icon fonts, SVG images (whether background or inline) will scale well regardless of screen size and pixel density. Browser support is generally good (IE9+) and file size is typically far lower than a PNG/JPG equivalent.
001 .svg .logo {
002 background-image: url(‘logo.svg’);
003 }
AUTHOR: Ben Frain