Las consultas de medios son geniales, pero…
Las consultas de medios son excelentes y una bendición para los desarrolladores de sitios web que desean realizar pequeños ajustes en sus hojas de estilo para brindar una mejor experiencia a los usuarios en dispositivos de varios tamaños. Básicamente, las consultas de medios te permiten personalizar el CSS de tu sitio según el tamaño de la pantalla. Antes de leer este artículo, obtén más información sobre el diseño responsivo y consulta algunos ejemplos del uso de consultas de medios aquí: mediaqueri.es.
Como señala Brad Frost en un artículo anterior, cambiar el aspecto es solo una de las muchas cosas que se deben tener en cuenta cuando se crea contenido para la Web móvil. Si lo único que haces cuando compilas tu sitio web para dispositivos móviles es personalizar el diseño con consultas de medios, se da la siguiente situación:
- Todos los dispositivos reciben el mismo JavaScript, CSS y recursos (imágenes, videos), lo que genera tiempos de carga más largos de lo necesario.
- Todos los dispositivos obtienen el mismo DOM inicial, lo que puede obligar a los desarrolladores a escribir CSS demasiado complicados.
- Poca flexibilidad para especificar interacciones personalizadas adaptadas a cada dispositivo.
Las apps web necesitan más que consultas de medios
No me malinterpretes. No odio el diseño responsivo a través de consultas de medios y, sin duda, creo que tiene un lugar en el mundo. Además, algunos de los problemas mencionados anteriormente se pueden resolver con enfoques como las imágenes responsivas, la carga dinámica de secuencias de comandos, etcétera. Sin embargo, en un momento determinado, es posible que realices demasiados ajustes incrementales y que sea mejor publicar diferentes versiones.
A medida que las IU que compilas aumentan en complejidad y te inclinas por las aplicaciones web de una sola página, querrás hacer más para personalizar las IU para cada tipo de dispositivo. En este artículo, aprenderás a realizar estas personalizaciones con el mínimo esfuerzo. El enfoque general implica clasificar el dispositivo del visitante en la clase de dispositivo correcta y publicar la versión adecuada para ese dispositivo, a la vez que se maximiza la reutilización del código entre las versiones.
¿A qué clases de dispositivos segmentas tu campaña?
Existen muchísimos dispositivos conectados a Internet, y casi todos tienen navegadores. La complicación radica en su diversidad: laptops Mac, estaciones de trabajo Windows, iPhones, iPads, teléfonos Android con entrada táctil, ruedas de desplazamiento, teclados, entrada de voz, dispositivos con sensibilidad a la presión, relojes inteligentes, tostadoras y refrigeradores, y muchos más. Algunos de estos dispositivos son omnipresentes, mientras que otros son muy raros.
Para crear una buena experiencia del usuario, debes saber quiénes son tus usuarios y qué dispositivos usan. Si compilas una interfaz de usuario para un usuario de computadora de escritorio con un mouse y un teclado, y se la das a un usuario de smartphone, tu interfaz será frustrante porque está diseñada para otro tamaño de pantalla y otra modalidad de entrada.
Existen dos extremos en el espectro de enfoques:
Crea una versión que funcione en todos los dispositivos. Como resultado, la UX se verá afectada, ya que los diferentes dispositivos tienen diferentes consideraciones de diseño.
Compila una versión para cada dispositivo que quieras admitir. Esto te llevará mucho tiempo, ya que compilarás demasiadas versiones de tu aplicación. Además, cuando llegue el próximo smartphone nuevo (lo que sucede aproximadamente cada semana), te verás obligado a crear otra versión.
Aquí hay una compensación fundamental: cuantas más categorías de dispositivos tengas, mejor será la experiencia del usuario que podrás ofrecer, pero más trabajo llevará diseñar, implementar y mantener.
Crear una versión separada para cada clase de dispositivo que decidas usar puede ser una buena idea por motivos de rendimiento o si las versiones que deseas publicar para las diferentes clases de dispositivos varían mucho. De lo contrario, el diseño web adaptable es un enfoque perfectamente razonable.
Una posible solución
Aquí tienes una solución: clasifica los dispositivos en categorías y diseña la mejor experiencia posible para cada categoría. Las categorías que elijas dependerán de tu producto y del usuario objetivo. A continuación, se muestra un ejemplo de clasificación que abarca de forma adecuada los dispositivos populares con capacidad web que existen actualmente.
- Pantallas pequeñas y táctiles (principalmente teléfonos)
- Pantallas grandes y táctiles (principalmente tablets)
- Pantallas grandes y teclado/mouse (principalmente computadoras de escritorio o laptops)
Este es solo uno de los muchos desgloses posibles, pero uno que tiene mucho sentido en el momento de escribir este artículo. En la lista anterior, faltan los dispositivos móviles sin pantallas táctiles (p. ej., teléfonos básicos y algunos lectores de libros electrónicos específicos). Sin embargo, la mayoría de estos dispositivos tienen instalada la navegación por teclado o el software de lector de pantalla, que funcionarán bien si creas tu sitio teniendo en cuenta la accesibilidad.
Ejemplos de apps web específicas para factores de forma
Existen muchos ejemplos de propiedades web que publican versiones completamente diferentes para distintos factores de forma. La Búsqueda de Google y Facebook lo hacen. Las consideraciones para esto incluyen el rendimiento (recuperación de recursos, renderización de páginas) y la experiencia del usuario más general.
En el mundo de las apps nativas, muchos desarrolladores optan por adaptar su experiencia a una clase de dispositivo. Por ejemplo, Flipboard para iPad tiene una IU muy diferente en comparación con Flipboard en iPhone. La versión para tabletas está optimizada para el uso con dos manos y el desplazamiento horizontal, mientras que la versión para teléfonos está diseñada para la interacción con una sola mano y el desplazamiento vertical. Muchas otras aplicaciones para iOS también proporcionan versiones para teléfonos y tablets significativamente diferentes, como Things (lista de tareas) y Showyou (videos sociales), que se muestran a continuación:
Enfoque 1: Detección del servidor
En el servidor, tenemos una comprensión mucho más limitada del dispositivo con el que estamos tratando. Probablemente, la pista más útil disponible sea la cadena de usuario-agente, que se proporciona a través del encabezado User-Agent en cada solicitud. Por este motivo, el mismo enfoque de detección de UA funcionará aquí. De hecho, los proyectos DeviceAtlas y WURFL ya lo hacen (y brindan mucha información adicional sobre el dispositivo).
Lamentablemente, cada una de ellas presenta sus propios desafíos. WURFL es muy grande y contiene 20 MB de XML, lo que puede generar una sobrecarga significativa del servidor para cada solicitud. Hay proyectos que dividen el XML por motivos de rendimiento. DeviceAtlas no es de código abierto y requiere una licencia pagada para su uso.
También hay alternativas gratuitas más sencillas, como el proyecto Detect Mobile Browsers. Por supuesto, la desventaja es que la detección de dispositivos inevitablemente será menos integral. Además, solo distingue entre dispositivos móviles y no móviles, y proporciona compatibilidad limitada con tablets solo a través de un conjunto de ajustes ad hoc.
Enfoque 2: Detección del cliente
Podemos obtener mucha información sobre el navegador y el dispositivo del usuario con la detección de funciones. Lo principal que debemos determinar es si el dispositivo tiene capacidad táctil y si es una pantalla grande o pequeña.
Debemos establecer un límite en algún punto para distinguir los dispositivos táctiles pequeños de los grandes. ¿Qué sucede con los casos extremos, como el Galaxy Note de 5"? En el siguiente gráfico, se muestran varios dispositivos populares de Android y iOS superpuestos (con las resoluciones de pantalla correspondientes). El asterisco indica que el dispositivo viene o puede venir en densidad doble. Aunque la densidad de píxeles se puede duplicar, CSS sigue informando los mismos tamaños.
Una breve aclaración sobre los píxeles en CSS: Los píxeles de CSS en la Web para dispositivos móviles no son los mismos que los píxeles de pantalla. Los dispositivos Retina de iOS introdujeron la práctica de duplicar la densidad de píxeles (p. ej., iPhone 3GS vs. 4, iPad 2 vs. 3). Los UA de Mobile Safari para Retina siguen informando el mismo ancho del dispositivo para evitar que se interrumpa la Web. Al igual que otros dispositivos (p. ej., Android) tienen pantallas de mayor resolución, utilizan el mismo truco de ancho del dispositivo.
Sin embargo, lo que complica esta decisión es la importancia de tener en cuenta los modos vertical y horizontal. No queremos volver a cargar la página ni cargar secuencias de comandos adicionales cada vez que reorientamos el dispositivo, aunque es posible que queramos renderizar la página de manera diferente.
En el siguiente diagrama, los cuadrados representan las dimensiones máximas de cada dispositivo, como resultado de superponer los contornos verticales y horizontales (y completar el cuadrado):
Si establecemos el umbral en 650px, clasificamos el iPhone y el Galaxy Nexus como "smalltouch", y el iPad y el Galaxy Tab como "tablet". En este caso, el Galaxy Note andrógino se clasifica como "teléfono" y obtendrá el diseño de teléfono.
Por lo tanto, una estrategia razonable podría verse así:
if (hasTouch) {
if (isSmall) {
device = PHONE;
} else {
device = TABLET;
}
} else {
device = DESKTOP;
}
Mira un ejemplo mínimo del enfoque de detección de funciones en acción.
El enfoque alternativo aquí es usar el reconocimiento de UA para detectar el tipo de dispositivo. Básicamente, creas un conjunto de heurísticas y las comparas con el navigator.userAgent de tu usuario. El pseudocódigo se ve así:
var ua = navigator.userAgent;
for (var re in RULES) {
if (ua.match(re)) {
device = RULES[re];
return;
}
}
Mira un ejemplo del enfoque de detección de UA en acción.
Nota sobre la carga del cliente
Si realizas la detección de UA en tu servidor, puedes decidir qué CSS, JavaScript y DOM publicar cuando recibas una solicitud nueva. Sin embargo, si realizas la detección del lado del cliente, la situación es más compleja. Tienes varias opciones:
- Redirige a una URL específica para el tipo de dispositivo que contiene la versión para este tipo de dispositivo.
- Carga de forma dinámica los recursos específicos del tipo de dispositivo.
El primer enfoque es sencillo y requiere un redireccionamiento como window.location.href = '/tablet'. Sin embargo, ahora la ubicación tendrá anexada esta información del tipo de dispositivo, por lo que te recomendamos que uses la API de History para limpiar tu URL. Lamentablemente, este enfoque implica un redireccionamiento, que puede ser lento, especialmente en dispositivos móviles.
El segundo enfoque es bastante más complejo de implementar. Necesitas un mecanismo para cargar CSS y JS de forma dinámica y, según el navegador, es posible que no puedas hacer cosas como personalizar <meta viewport>. Además, como no hay redireccionamiento, te quedas con el HTML original que se publicó. Por supuesto, puedes manipularlo con JavaScript, pero esto puede ser lento o poco elegante, según tu aplicación.
Decide si es cliente o servidor
Estas son las ventajas y desventajas de cada enfoque:
Cliente profesional:
- Es más compatible con el futuro, ya que se basa en los tamaños y las capacidades de la pantalla, en lugar de en UA.
- No es necesario actualizar la lista de UA de forma constante.
Servidor Pro:
- Control total de qué versión se entrega a qué dispositivos
- Mejor rendimiento: No es necesario redireccionar al cliente ni cargar contenido de forma dinámica.
Mi preferencia personal es comenzar con device.js y la detección del cliente. A medida que evoluciona tu aplicación, si detectas que el redireccionamiento del cliente es una desventaja significativa en el rendimiento, puedes quitar fácilmente el script device.js y, luego, implementar la detección de UA en el servidor.
Presentamos device.js
Device.js es un punto de partida para realizar la detección semántica de dispositivos basada en consultas de medios sin necesidad de una configuración especial del servidor, lo que ahorra el tiempo y el esfuerzo necesarios para analizar la cadena del agente de usuario.
La idea es que proporciones un lenguaje de marcado compatible con los motores de búsqueda (link rel=alternate) en la parte superior de tu <head> para indicar qué versiones de tu sitio deseas proporcionar.
<link rel="alternate" href="http://foo.com" id="desktop"
media="only screen and (touch-enabled: 0)">
A continuación, puedes realizar la detección de UA del servidor y controlar el redireccionamiento de versiones por tu cuenta, o bien usar el script device.js para realizar el redireccionamiento del cliente basado en funciones.
Para obtener más información, consulta la página del proyecto device.js y también una aplicación falsa que usa device.js para el redireccionamiento del cliente.
Recomendación: MVC con vistas específicas para cada factor de forma
A esta altura, probablemente pienses que te estoy diciendo que compiles tres apps completamente separadas, una para cada tipo de dispositivo. ¡No! El uso compartido de códigos es la clave.
Esperamos que hayas estado usando un framework similar a MVC, como Backbone, Ember, etcétera. Si es así, conoces el principio de separación de responsabilidades, específicamente que tu IU (capa de vista) debe estar desacoplada de tu lógica (capa de modelo). Si es la primera vez que usas MVC, comienza con algunos de estos recursos sobre MVC y MVC en JavaScript.
La historia de varios dispositivos se adapta perfectamente a tu framework de MVC existente. Puedes mover fácilmente tus vistas a archivos separados y crear una vista personalizada para cada tipo de dispositivo. Luego, puedes publicar el mismo código en todos los dispositivos, excepto en la capa de vista.
Tu proyecto podría tener la siguiente estructura (por supuesto, puedes elegir la estructura que tenga más sentido según tu aplicación):
models/ (modelos compartidos) item.js item-collection.js
controllers/ (controladores compartidos) item-controller.js
versions/ (contenido específico del dispositivo) tablet/ desktop/ phone/ (código específico del teléfono) style.css index.html views/ item.js item-list.js
Este tipo de estructura te permite controlar por completo qué recursos carga cada versión, ya que tienes HTML, CSS y JavaScript personalizados para cada dispositivo. Esto es muy potente y puede generar la forma más eficiente y con mejor rendimiento de desarrollar para la Web en varios dispositivos, sin depender de trucos como las imágenes adaptables.
Una vez que ejecutes tu herramienta de compilación favorita, concatenarás y reducirás todo tu código JavaScript y CSS en archivos únicos para una carga más rápida, y tu HTML de producción se verá similar al siguiente (para teléfonos, con device.js):
<!doctype html>
<head>
<title>Mobile Web Rocks! (Phone Edition)</title>
<!-- Every version of your webapp should include a list of all
versions. -->
<link rel="alternate" href="http://foo.com" id="desktop"
media="only screen and (touch-enabled: 0)">
<link rel="alternate" href="http://m.foo.com" id="phone"
media="only screen and (max-device-width: 650px)">
<link rel="alternate" href="http://tablet.foo.com" id="tablet"
media="only screen and (min-device-width: 650px)">
<!-- Viewport is very important, since it affects results of media
query matching. -->
<meta name="viewport" content="width=device-width">
<!-- Include device.js in each version for redirection. -->
<script src="device.js"></script>
<link rel="style" href="phone.min.css">
</head>
<body>
<script src="phone.min.js"></script>
</body>
Ten en cuenta que la consulta de medios (touch-enabled: 0) no es estándar (solo se implementa en Firefox detrás de un prefijo de proveedor moz), pero device.js la controla correctamente (gracias a Modernizr.touch).
Anulación de versión
A veces, la detección de dispositivos puede fallar y, en algunos casos, es posible que un usuario prefiera ver el diseño de la tablet en su teléfono (quizás esté usando un Galaxy Note), por lo que es importante que les des a los usuarios la opción de elegir qué versión de tu sitio usar si desean anular la configuración manualmente.
El enfoque habitual es proporcionar un vínculo a la versión para computadoras de escritorio desde la versión para dispositivos móviles. Esto es bastante fácil de implementar, pero device.js admite esta funcionalidad con el parámetro GET device.
Conclusión
En resumen, cuando crees IU de una sola página para varios dispositivos que no se ajusten perfectamente al mundo del diseño responsivo, haz lo siguiente:
- Elige un conjunto de clases de dispositivos para admitir y los criterios con los que clasificar los dispositivos en clases.
- Crea tu app de MVC con una clara separación de responsabilidades, dividiendo las vistas del resto de la base de código.
- Usa device.js para detectar la clase de dispositivo del cliente.
- Cuando esté todo listo, empaqueta tu secuencia de comandos y hojas de estilo en uno de cada uno por clase de dispositivo.
- Si el rendimiento del redireccionamiento del cliente es un problema, abandona device.js y cambia a la detección de UA del servidor.