Las consultas de medios son excelentes, pero…
Las consultas de medios son increíbles, un regalo del cielo 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. En esencia, las consultas de medios te permiten personalizar el CSS de tu sitio según el tamaño de la pantalla. Antes de comenzar a leer este artículo, obtén más información sobre el diseño responsivo y consulta algunos ejemplos excelentes del uso de las consultas de medios aquí: mediaqueri.es.
Como Brad Frost señala 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 produce la siguiente situación:
- Todos los dispositivos obtienen 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 podría 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 imágenes responsivas, carga de secuencias de comandos dinámicas, etc. Sin embargo, en un momento determinado, es posible que estés haciendo demasiados ajustes incrementales y que sea mejor publicar diferentes versiones.
A medida que las IU que compilas aumentan de complejidad y te inclinas hacia las webapps 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 de tu visitante en la clase correcta y entregarle la versión adecuada, a la vez que se maximiza la reutilización de código entre las versiones.
¿A qué clases de dispositivos te orientas?
Existen muchos dispositivos conectados a Internet, y casi todos tienen navegadores. La complicación reside en su diversidad: laptops Mac, estaciones de trabajo de 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 computadoras 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.
Hay dos extremos en el espectro de enfoques:
Compila una versión que funcione en todos los dispositivos. Como resultado, la UX sufrirá, ya que los diferentes dispositivos tienen diferentes consideraciones de diseño.
Compila una versión para cada dispositivo que quieras admitir. Esto 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), deberás 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 puedas ofrecer, pero más trabajo requerirá el diseño, la implementación y el mantenimiento.
Crear una versión independiente para cada clase de dispositivo que elijas puede ser una buena idea por motivos de rendimiento o si las versiones que deseas publicar para diferentes clases de dispositivos varían mucho. De lo contrario, el diseño web responsivo 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 una de ellas. Las categorías que elijas dependen de tu producto y del usuario objetivo. Esta es una clasificación de muestra que abarca de forma muy conveniente los dispositivos populares compatibles con la Web que existen en la actualidad.
- pantallas pequeñas y táctiles (en su mayoría, teléfonos)
- pantallas grandes y táctiles (principalmente tablets)
- pantallas grandes + teclado/mouse (principalmente computadoras de escritorio o laptops)
Esta es solo una de las muchas posibles descomposturas, pero es una 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 con funciones básicas y algunos lectores de libros electrónicos dedicados). Sin embargo, la mayoría de ellos tienen instalado software de navegación con teclado o lector de pantalla, que funcionará bien si compilas tu sitio teniendo en cuenta la accesibilidad.
Ejemplos de apps web específicas del factor de forma
Existen muchos ejemplos de propiedades web que publican versiones completamente diferentes para diferentes factores de forma. La Búsqueda de Google lo hace, al igual que Facebook. 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 para iPhone. La versión para tablets está optimizada para el uso con dos manos y el giro horizontal, mientras que la versión para teléfonos está diseñada para la interacción con una sola mano y el giro vertical. Muchas otras aplicaciones para iOS también proporcionan versiones muy diferentes para teléfonos y tablets, como Things (lista de tareas) y Showyou (video social), 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 lo tanto, el mismo enfoque de espionaje de UA funcionará aquí. De hecho, los proyectos DeviceAtlas y WURFL ya lo hacen (y proporcionan 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 podría 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 y más simples, como el proyecto Detect Mobile Browsers. La desventaja, por supuesto, es que la detección de dispositivos será, inevitablemente, menos integral. Además, solo distingue entre dispositivos móviles y no móviles, lo que 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 mediante la detección de atributos. Lo principal que debemos determinar es si el dispositivo tiene capacidad táctil y si tiene una pantalla grande o pequeña.
Necesitamos trazar la línea en algún lugar para distinguir los dispositivos táctiles pequeños y 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 con densidad doble. Aunque la densidad de píxeles se pueda duplicar, CSS sigue informando los mismos tamaños.
A modo de referencia, los píxeles en CSS de la Web móvil no son los mismos que los píxeles de la pantalla. Los dispositivos Retina de iOS introdujeron la práctica de duplicar la densidad de píxeles (p. ej., iPhone 3GS en comparación con el 4, iPad 2 en comparación con el 3). Las UAs de Safari para dispositivos móviles retina aún informan el mismo ancho de dispositivo para evitar que se produzcan errores en la Web. Como otros dispositivos (p. ej., Android) obtienen pantallas de mayor resolución, hacen el mismo truco de ancho del dispositivo.
Sin embargo, lo que complica esta decisión es la importancia de considerar 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 deseemos 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 configuramos el umbral en 650px
, clasificamos el iPhone y el Galaxy Nexus como "pantalla táctil pequeña", y el iPad y la 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 ser la siguiente:
if (hasTouch) {
if (isSmall) {
device = PHONE;
} else {
device = TABLET;
}
} else {
device = DESKTOP;
}
Consulta una muestra mínima del enfoque de detección de características en acción.
El enfoque alternativo aquí es usar el espionaje 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 de la siguiente manera:
var ua = navigator.userAgent;
for (var re in RULES) {
if (ua.match(re)) {
device = RULES[re];
return;
}
}
Consulta 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 recibes una solicitud nueva. Sin embargo, si realizas la detección del cliente, la situación es más compleja. Tienes varias opciones:
- Redirecciona a una URL específica del tipo de dispositivo que contenga 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, la ubicación ahora tendrá esta información del tipo de dispositivo adjunta, 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, en especial en dispositivos móviles.
El segundo enfoque es mucho 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 realizar acciones como personalizar <meta viewport>
. Además, como no hay redireccionamiento, te quedas con el HTML original que se entregó. Por supuesto, puedes manipularlo con JavaScript, pero esto puede ser lento o poco elegante, según tu aplicación.
Cómo decidir si se trata de un cliente o un servidor
Estas son las compensaciones entre los enfoques:
Cliente profesional:
- Es más resistente a los cambios futuros, ya que se basa en los tamaños o las capacidades de la pantalla en lugar de UA.
- No es necesario actualizar constantemente la lista de UA.
Pro Server:
- Control total de qué versión se entrega a qué dispositivos
- Mejor rendimiento: No se necesitan redireccionamientos de clientes ni cargas dinámicas.
Mi preferencia personal es comenzar con device.js y la detección del cliente. A medida que tu aplicación evolucione, si consideras que el redireccionamiento del cliente es un inconveniente de rendimiento significativo, puedes quitar fácilmente la secuencia de comandos device.js e implementar la detección de UA en el servidor.
Presentamos device.js
Device.js es un punto de partida para realizar la detección de dispositivos semántica 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 cadenas de usuario-agente.
La idea es que proporciones un marcado compatible con los motores de búsqueda (link rel=alternate) en la parte superior de tu <head>
que indique 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 versión por tu cuenta, o bien usar la secuencia de comandos device.js para realizar el redireccionamiento del cliente basado en funciones.
Para obtener más información, consulta la página del proyecto de device.js y una aplicación falsa que usa device.js para la redirección del cliente.
Recomendación: MVC con vistas específicas del factor de forma
Es probable que, a estas alturas, estés pensando que te estoy diciendo que crees tres apps completamente separadas, una para cada tipo de dispositivo. ¡No! El uso compartido de código es la clave.
Espero que hayas estado usando un framework similar a MVC, como Backbone, Ember, etc. Si es así, conoces el principio de separación de preocupaciones, 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 multidispositivo se ajusta perfectamente a tu framework de MVC existente. Puedes mover tus vistas fácilmente 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 que sea más adecuada según tu aplicación):
models/ (modelos compartidos) item.js item-collection.js
controllers/ (controladores compartidos) item-controller.js
versions/ (device-specific stuff) tablet/ desktop/ phone/ (phone-specific code) style.css index.html views/ item.js item-list.js
Este tipo de estructura te permite controlar por completo los recursos que 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 de mejor rendimiento de desarrollar para la Web multidispositivo, 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 el código JavaScript y CSS en archivos únicos para una carga más rápida, y tu HTML de producción se verá de la siguiente manera (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, un usuario puede preferir ver el diseño de la tablet en su teléfono (quizás use un Galaxy Note), por lo que es importante darles a los usuarios la opción de elegir qué versión de tu sitio usar si quieren anularla de forma manual.
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 multidispositivo que no se ajusten bien al mundo del diseño responsivo, haz lo siguiente:
- Elige un conjunto de clases de dispositivos que admitirás y los criterios con los que clasificarás los dispositivos en clases.
- Compila tu app de MVC con una separación clara de responsabilidades y divide las vistas del resto de la base de código.
- Usa device.js para realizar la detección de clases de dispositivos del cliente.
- Cuando todo esté listo, empaqueta tu secuencia de comandos y hojas de estilo en una de cada clase por dispositivo.
- Si el rendimiento del redireccionamiento del cliente es un problema, abandona device.js y cambia a la detección de UA del servidor.