Hacia una web para Retina

[Fuente: http://coding.smashingmagazine.com/2012/08/20/towards-retina-web/]

Con el reciente anuncio y versión del Retina Macbook Pro, Apple ha introducido las pantallas de doble densidad a todas las categorias de productos en sus lineas de ventas, allanando el camino a la nueva generación de estandares de pantalla. Mientras el iPhone de cuarta generación nos ofreció lo que era Web en modo “no-Retina” en 2010, hemos tenido que esperar a la tercera generación de iPad para darnos cuenta de lo anticuados que están nuestros gráficos e imágenes de contenido.

En los confines del jardin de Apple, las apps nativas son actualizadas con los gráficos Retina de una forma eficaz, con la ayuda de un sólido SDK y de un proceso de transición bien documentado. Por contraste, la Web al tener una naturaleza tan abierta hace que la transición a displays de alta densidad sea lento y doloroso. En la ausencia de estandares ampliamente aceptados por la industria para hacer eficaz este proceso, cada diseñador/programador Web se le deja la responsabilidad de que sus usuarios tengan la mejor experiencia de usuario, independientemente del tipo de pantalla que estén utilizando.

Antes de entrar en materia, veamos brevemente algunas nociones básicas que son claves para entender los retos y restricciones de diseñar para múltiples densidades de pantalla.

Los píxeles de los dispositivos

Device Pixels

Un pixel de dispositivo (o pixel físico) es la unidad más pequeña en una pantalla. Cada pixel configura su propio color y brillo como le va diciendo el sistema operativo. La impreceptible distancia entre puntos minusculos hace el efecto optico de percibir la imagen de forma completa y contínua.

La densidad de la pantalla se refiere al número de píxeles de dispositivo en un superficie física. Es a menudo medido en pixeles por pulgada (PPI). Apple ha acuñado el término “Retina” para sus pantallas de doble densidad, haciendo que el ojo humano no pueda ni de lejos distinguir píxeles individuales en la pantalla desde una distancia de visionado “normal”.

Los píxeles CSS

CSS Pixels

Un pixel CSS es un unidad abstracta utilizada por los navegadores para dibujar contenido de forma precisa y consistente en las páginas Web. Genericamente, los píxeles CSS se refieren a píxeles independientes del dispositivo (DIPs). En pantallas de densidad estandar, 1 pixel CSS se corresponde con el pixel de dispositivo.

<div height="200" width="300"></div>

Esto utilizaría una caja de 200×300 de píxeles de dispositivo para ser dibujado en la pantalla. En la pantalla Retina, el mismo div utiliza 400×600 para que salga del mismo tamaño, resultando en cuatro veces más píxeles, como mostramos en la siguiente figura:

Device Pixels In Retina Displays

En un pantalla Retina , para cubrir la misma superficie física se utiliza 4 veces más de píxeles de dispositivo

La proporción entre los pixeles de dispositivo y los pixeles de CSS puede obtenerse utilizando el siguiente media query y sus equivalentes especificos del vendedor:

	 device-pixel-ratio,
	 -o-device-pixel-ratio,
	 -moz-device-pixel-ratio,
	-Webkit-device-pixel-ratio {
	…
	}

O puedes utilizar sus primos hermanos que vendrán en un futuro:

device-pixel-ratio,
	 -o-min-device-pixel-ratio,
	 min--moz-device-pixel-ratio,
	-Webkit-min-device-pixel-ratio {
	…
}

En Javascript ,  window.devicePixelRatio puede ser utilizado para obtener el mismo ratio, aunque no todos los navegadores lo soportan. Ambas técnicas serán discutidas en más profundidad en este artículo.

Así por ejemplo podemos decirle a una pagina web que utilice una hoja de estilos diferente en caso de pantallas de alta densidad:

<!-- 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)' />

o dentro de una hoja de estilos:

/* iPhone 4 ----------- */
@media
only screen and (-webkit-min-device-pixel-ratio : 1.5),
only screen and (min-device-pixel-ratio : 1.5) {
/* Styles */
}

 

Los pixeles Bitmap

Bitmap Pixels

Un pixel de bitmap es la unidad más pequeña de datos de una imagen raster (PNG. GIF, JPG, etc). Cada pixel contien información sobre cómo debe ser mostrado, incluyendo su posición en el sistema de coordenadas de la imagen y su color. Algunos formatos de imágenes pueden almacenar datos adicionales por pixel, tales como la opacidad (lo que se llama el canal alpha).

Además de la resolución raster, una imagen de la web tiene un tamaño abstracto,  definido en pixeles CSS. El browser ensancha o estrecha la imagen basándose en el height y el width CSS mientras está dibujando la imagen.

Cuando una imagen raster se muestra a tamaño completo en una pantalla de densidad estandar, 1 pixel de bitmap se correspondecon 1 pixel de dispositivo, resultando en una representación completamente fiel. Como el pixel de un bitmap no puede ser dividido, es multiplicado por 4 en las pantallas Retina para preservar el mismo tamaño físico de la imagen, perdiendo detalle en el camino.

Bitmap Pixels On Retina Displays

Each bitmap pixel gets multiplied by four to fill the same physical surface on a Retina display.

La herramienta Pecho (Tool Chest)

Incluso aunque estamos en el camino de un cambio, hay varias aproximaciones para optimizar los gráficos para pantallas Retina , y más que estarán saliendo en el mismo momento que se lee esto. Cada método hace algún grado de compromiso entre al rendimiento, facilidad de implementación y soporte multinavegador (corss-browser). Por tanto , elegir la herramienta debe ser analizado caso por caso, teniendo en cuenta tanto los factores cuantitativos como los cualitativos.

 

El tamaño en HTML y CSS

La forma más directa de servir gráficos web preparados para Retina es reducir a la mitad el tamaño de tus imagenes raster utilizando CSS o HTML,  o manualmente o programaticamente. Por ejemplo. para servir una imagen de 200×300 pixeles (recuerda pixeles CSS), deberiamos subir una imagen con una resolución de bitmap de 400×600 al servidor, entonces reducirla al 50% utilizando CSS o atributos HTML. En una pantalla estandar , el resultado seria una imagen renderizada con cuatro veces menos pixeles que el tamño completo del bitmap – un proceso que es conocido como “downsampling

How downsampling works

A CSS-sized image gets its dimensions halved during the rendering process.

Debido a que la misma imagen en una pantalla Retina utiliza 4 veces más pixeles , cada pixel físico termina coincidiendo exactamente con un pixel del bitmap , permitiendo que la imagen se dibuje completamente fiel.

How HTML sizing works

CSS-sized images regain their full-detail glory on Retina displays.

Hay varias formas de conseguir esto:

USING HTML

The easiest way to apply CSS sizing would be by using the width and height attributes of the img tag:

1 <img src="example@2x.png" width="200" height="300" />

Please note that, even though specifying height is optional, it allows the browser to reserve the space required for the image before loading it. This prevents the page layout from changing as the image loads.

What to use it for? Single-page websites with few content images.

USING JAVASCRIPT

The same result can also be obtained using Javascript by targeting all Retina-ready content images in the document and halving their sizes. With the help of jQuery, this would look like this:

1 $(window).load(function() {
2 var images = $('img');
3 images.each(function(i) {
4 $(this).width($(this).width() / 2);
5 });
6 });

What to use it for? Websites with few content images.

USING CSS (SCSS)

If you want to keep all of the presentation code in your CSS files, then the most common technique involves setting the image as the background of another HTML element, usually a div, then specifying its background-size property. You could either set explicit width and height values for the background image or use the contain value if the dimensions of the HTML element are already specified. It is worth noting that the background-size property is not supported in IE 7 or 8.

1 .image {
2 background-image: url(example@2x.png);
3 background-size: 200px 300px;
4 /* Alternatively background-size: contain; */
5 height: 300px;
6 width: 200px;
7 }

You could also target a :before or :after pseudo-element instead:

1 .image-container:before {
2 background-image: url(example@2x.png);
3 background-size: 200px 300px;
4 content:'';
5 display: block;
6 height: 300px;
7 width: 200px;
8 }

This technique works just as well with CSS sprites, as long as the background-position is specified relatively to the CSS size (200 × 300 pixels in this case):

01 .icon {
02 background-image: url(example@2x.png);
03 background-size: 200px 300px;
04 height: 25px;
05 width: 25px;
06
07 &.trash {
08 background-position: 25px 0;
09 }
10
11 &.edit {
12 background-position: 25px 25px;
13 }
14 }

When using image sprites, consider any OS-specific limitations.

What to use it for? Websites that make limited use of the background-image property, such as those that rely on a single-image sprite.

HTML AND CSS SIZING: PROS

  • Easy to implement
  • Cross-browser compatible

HTML AND CSS SIZING: CONS

  • Non-Retina devices have to download larger assets.
  • Downsampled images might lose some of their sharpness on standard-density screens, depending on the algorithm used.
  • The background-size property is not supported in IE 7 or 8.

Querying Pixel Density

Querying Pixel Density

Perhaps the most popular way to serve Retina-ready graphics on the Web is by querying the device for its pixel density and then serving assets accordingly. This can be done using either CSS or JavaScript.

USING CSS MEDIA QUERIES

As of this writing, almost every major browser vendor has implemented a prefixed variant of device-pixel-ratio and its two siblings, min-device-pixel-ratio and max-device-pixel-ratio. These media queries can be used in conjunction with the background-imageproperty to serve Retina-ready assets to high-density devices:

01 .icon {
02 background-image: url(example.png);
03 background-size: 200px 300px;
04 height: 300px;
05 width: 200px;
06 }
07
08 @media only screen and (-Webkit-min-device-pixel-ratio: 1.5),
09 only screen and (-moz-min-device-pixel-ratio: 1.5),
10 only screen and (-o-min-device-pixel-ratio: 3/2),
11 only screen and (min-device-pixel-ratio: 1.5) {
12 .icon {
13 background-image: url(example@2x.png);
14 }
15 }

By using a ratio of 1.5 instead of 2, you can target other non-Apple devices with the same query.

What to use it for? Any website or app that uses the background-image property for graphic assets. Not suitable for content images.

CSS QUERYING: PROS

  • Devices download only those assets that target them.
  • Cross-browser compatible
  • Pixel-precise control

CSS QUERYING: CONS

  • Tedious to implement, especially on large websites.
  • Displaying content images as backgrounds of other HTML elements is semantically incorrect.

USING JAVASCRIPT

The pixel density of the screen can be queried in Javascript usingwindow.devicePixelRatio, which reports the same value as its CSS counterpart. Once a higher-density screen is identified, you can replace every inline image with its Retina counterpart:

01 $(document).ready(function(){
02 if (window.devicePixelRatio > 1) {
03 var lowresImages = $('img');
04
05 images.each(function(i) {
06 var lowres = $(this).attr('src');
07 var highres = lowres.replace(".", "@2x.");
08 $(this).attr('src', highres);
09 });
10 }
11 });

Retina.js is a Javascript plugin that implements roughly the same technique as described above, with some additional features, such as skipping external images and skipping internal images with no @2x counterparts.

Lastly, it is worth noting that devicePixelRatio is not entirely cross-browser compatible.

What to use it for? Any website with content images, such as landing pages and blogs.

JAVASCRIPT QUERYING: PROS

  • Easy to implement
  • Non-Retina devices do not download large assets.
  • Pixel-precise control

JAVASCRIPT QUERYING: CONS

  • Retina devices have to download both standard- and high-resolution images.
  • The image-swapping effect is visible on Retina devices.
  • Does not work on some popular browsers (such as IE and Firefox).

Scalable Vector Graphics

Scalable Vector Graphics

Regardless of the method used, raster images remain inherently constrained by their bitmap resolution; they were never meant to be infinitely scalable. This is where vector graphics have the advantage, being a future-proof way to “Retinize” your Web graphics.

As of this writing, the vector XML-based SVG format has cross-browser support of more than 70% and can be used in several ways on the Web. SVG images can be easily created in and exported from a number of vector-graphic editors, such as Adobe Illustrator and free alternatives such as Inkscape.

As far as Web design goes, the most straightforward way to use SVG assets is with the HTML img tag or with the CSS background-image and content:url() properties.

1 <img src="example.svg" width="200" height="300" />

In the example above, a single SVG image can be used as a universal asset, scaling infinitely up or down as required. This not only saves precious bandwidth (most SVG files tend to be smaller in size than standard-resolution PNGs), but also makes your graphic assets much easier to maintain. The same would apply if used in CSS:

01 /* Using background-image */
02
03 .image {
04 background-image: url(example.svg);
05 background-size: 200px 300px;
06 height: 200px;
07 width: 300px;
08 }
09
10 /* Using content:url() */
11
12 .image-container:before {
13 content: url(example.svg);
14 /* width and height do not work with content:url() */
15 }

If you have to support IE 7 or 8 or Android 2.x, then you will need a fallback solution that swaps SVG images with their PNG counterparts. This can be easily done with Modernizr:

01 .image {
02 background-image: url(example.png);
03 background-size: 200px 300px;
04 }
05
06 .svg {
07 .image {
08 background-image: url(example.svg);
09 }
10 }

For best cross-browser results and to avoid some rasterization headaches in Firefox and Opera, make each SVG image at least the size of its parent HTML element.

In HTML, you can implement a similar fallback solution by adding a custom data attribute to your img tag:

1 <img src="example.svg" data-png-fallback="example.png" />

Then, handle the rest with jQuery and Modernizr:

1 $(document).ready(function(){
2 if(!Modernizr.svg) {
3 var images = $('img[data-png-fallback]');
4 images.each(function(i) {
5 $(this).attr('src', $(this).data('png-fallback'));
6 });
7 }
8 });

This HTML and JavaScript route, however, would not prevent browsers with no SVG support from downloading the SVG assets.

What to use it for? Any website or app. Suitable for icons, logos and simple vector illustrations.

SVG: PROS

  • One universal asset for all devices
  • Easy to maintain
  • Future-proof: infinitely scalable vector graphics

SVG: CONS

  • No pixel precision due to anti-aliasing
  • Unsuitable for complex graphics due to large file sizes
  • No native support in IE 7 and 8 or early Android versions

Icon Fonts

Icon Fonts

Popularized by Twitter’s Bootstrap, the technique of using @font-face with icon-based fonts has garnered a following of its own as a resolution-independent alternative to bitmap icons. The technique consists of using a custom Web font that replaces the alphabet with monochrome glyphs, which can be styled using CSS, just like any other text on the website.

There is no shortage of comprehensive, good-quality icon fonts that would cover most of your needs. That being said, importing a large font in half a dozen formats only to use a small subset of the icons is a bad idea. Consider building your own custom font with free tools such as FontelloFont Builder or even Inkscape.

The most common way to use icon fonts on websites is by assigning an .icon or .glyphclass to a particular HTML element — most often a <span> or an <i> — and then using the letter corresponding to the desired icon as its content:

1 <span class="icon">a</span>

After having imported your custom font using @font-face, you would declare it:

1 .icon {
2 font-family: 'My Icon Font';
3 }

Another technique consists of using the :before pseudo-element and the contentproperty, with a unique class for each icon:

1 <span class="glyph-heart"></span>
1 [class^="glyph-"]:before {
2 font-family: 'My Icon Font';
3 }
4
5 .glyph-heart:before {
6 content: 'h';
7 }

What to use it for? Websites or apps with a high number of icons, and for rapid prototyping.

ICON FONTS: PROS

  • Future-proof: infinitely scalable glyphs
  • Cross-browser compatible
  • More flexible than graphic assets: can be used in placeholder text and other form elements, etc.

ICON FONTS: CONS

  • No pixel precision due to subpixel anti-aliasing
  • Hard to maintain: changing a single icon requires regenerating the whole font.
  • Relies on semantically incorrect markup (unless used with :before or :afterpseudo-elements).

Favicons

Favicons are getting their fair share of attention, being increasingly used outside of browser chrome as an iconic representation of our websites and apps. To make your favicons Retina-ready, export an .ico file in both 16- and 32-pixel versions. If you are using a Mac, you can create your own .ico files with Apple’s Icon Composer (included in theGraphic Tools in Xcode) or with Icon Slate, a paid third-party application.

A Glimpse Of The Future

Besides the techniques covered above, several other efforts are being made independently by organizations and individuals alike, not the least of which is Apple’s own-Webkit-image-setintroduced last spring. This proposal allows for multiple variants of the same image to be provided in one CSS declaration:

1 .image {
2 background-image: -Webkit-image-set(url(example.png) 1x, url(example@2x.png) 2x);
3 background-size: 200px 300px;
4 }

This technique does not, however, cover images inside img tags, and it is Webkit-only as of this writing.

Another notable effort is Scott Jehl’s Picturefill, an HTML and Javascript solution that makes heavy use of data attributes and media queries to serve different images in different media contexts.

1 <div data-picture>
2 <div data-src="example.png"></div>
3 <div data-src="example@2x.png" data-media="(min-device-pixel-ratio: 1.5)"></div>
4
5 <!-- Fallback content for non-JS browsers -->
6 <noscript>
7 <img src="example.png" >
8 </noscript>
9 </div>

Even if the markup puts you off, it is a good cross-browser solution to consider if you are dealing with few content images.

Last but not least, the ambitious picture element proposal aims to bring responsive images to the Web using a markup-only approach for multiple image sources, coupled with media queries that route each device to the right asset.

CLOSING WORDS

Like other major shifts the Web is currently undergoing, attaining resolution independence will be a long journey. As Web designers and developers, either we can sit down and wait passively for a convention to be standardized, or we can immediately start offering a pleasurable viewing experience to our users. Let’s get to work.

(al)