[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
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
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:
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
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.
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”
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.
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 () { |
3 |
images.each( function (i) { |
4 |
$( this ).width($( this ).width() / 2); |
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.
2 |
background-image : url (example@ 2 x.png); |
3 |
background- size : 200px 300px ; |
4 |
/* Alternatively background-size: contain; */ |
You could also target a :before
or :after
pseudo-element instead:
1 |
.image-container:before { |
2 |
background-image : url (example@ 2 x.png); |
3 |
background- size : 200px 300px ; |
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):
02 |
background-image : url (example@ 2 x.png); |
03 |
background- size : 200px 300px ; |
08 |
background-position : 25px 0 ; |
12 |
background-position : 25px 25px ; |
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
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-image
property to serve Retina-ready assets to high-density devices:
02 |
background-image : url (example.png); |
03 |
background- size : 200px 300px ; |
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 ) { |
13 |
background-image : url (example@ 2 x.png); |
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' ); |
05 |
images.each( function (i) { |
06 |
var lowres = $( this ).attr( 'src' ); |
07 |
var highres = lowres.replace( "." , "@2x." ); |
08 |
$( this ).attr( 'src' , highres); |
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
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 */ |
04 |
background-image : url (example.svg); |
05 |
background- size : 200px 300px ; |
10 |
/* Using content:url() */ |
12 |
.image-container:before { |
13 |
content : url (example.svg); |
14 |
/* width and height do not work with content:url() */ |
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:
02 |
background-image : url (example.png); |
03 |
background- size : 200px 300px ; |
08 |
background-image : url (example.svg); |
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 (){ |
3 |
var images = $( 'img[data-png-fallback]' ); |
4 |
images.each( function (i) { |
5 |
$( this ).attr( 'src' , $( this ).data( 'png-fallback' )); |
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
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 Fontello, Font Builder or even Inkscape.
The most common way to use icon fonts on websites is by assigning an .icon
or .glyph
class 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:
2 |
font-family : 'My Icon Font' ; |
Another technique consists of using the :before
pseudo-element and the content
property, with a unique class for each icon:
1 |
< span class = "glyph-heart" ></ span > |
1 |
[class^= "glyph-" ]:before { |
2 |
font-family : 'My Icon Font' ; |
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 :after
pseudo-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-set
, introduced last spring. This proposal allows for multiple variants of the same image to be provided in one CSS declaration:
2 |
background-image : -Webkit-image-set( url (example.png) 1 x, url (example@ 2 x.png) 2 x); |
3 |
background- size : 200px 300px ; |
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.
2 |
< div data-src = "example.png" ></ div > |
3 |
< div data-src = "example@2x.png" data-media = "(min-device-pixel-ratio: 1.5)" ></ div > |
5 |
<!-- Fallback content for non-JS browsers --> |
7 |
< img src = "example.png" > |
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)