Une approche non réactive de la création d'applications Web inter-appareils

Boris Smus
Boris Smus

Les requêtes média sont utiles, mais...

Les requêtes média sont géniales. Elles sont une excellente aide pour les développeurs de sites Web qui souhaitent apporter de légères modifications à leurs feuilles de style afin d'améliorer l'expérience des utilisateurs sur des appareils de différentes tailles. Les requêtes média vous permettent essentiellement de personnaliser le CSS de votre site en fonction de la taille de l'écran. Avant de vous plonger dans cet article, découvrez le responsive design et consultez quelques exemples d'utilisation de requêtes média ici: mediaqueri.es.

Comme le souligne Brad Frost dans un article précédent, la modification de l'apparence n'est que l'un des nombreux éléments à prendre en compte lors de la conception du Web pour mobile. Si la seule chose que vous devez faire lors de la création de votre site Web mobile est de personnaliser votre mise en page avec des requêtes média, nous avons la situation suivante:

  • Tous les appareils utilisent le même code JavaScript, le même CSS et les mêmes éléments (images, vidéos), ce qui entraîne des temps de chargement plus longs que nécessaire.
  • Tous les appareils reçoivent le même DOM initial, ce qui peut obliger les développeurs à écrire des code CSS trop compliqués.
  • Peu de flexibilité dans la spécification d'interactions personnalisées adaptées à chaque appareil.

Les applications Web nécessitent plus que des requêtes média

Ne vous méprenez pas. Je ne déteste pas le responsive design via les requêtes média, et je pense certainement qu'il a sa place dans le monde. En outre, certains des problèmes mentionnés ci-dessus peuvent être résolus à l'aide d'approches telles que les images responsives, le chargement dynamique de scripts, etc. Cependant, à un moment donné, vous pouvez être amené à effectuer trop d'ajustements incrémentiels, et il peut être préférable de diffuser différentes versions.

À mesure que les interfaces utilisateur que vous créez gagnent en complexité et que vous vous tournez vers les applications Web monopages, vous devez en faire plus pour personnaliser les interfaces utilisateur pour chaque type d'appareil. Cet article vous explique comment effectuer ces personnalisations avec un minimum d'efforts. L'approche générale consiste à classer l'appareil du visiteur dans la classe d'appareil appropriée et à diffuser la version appropriée sur cet appareil, tout en optimisant la réutilisation du code entre les versions.

Quelles catégories d'appareils ciblez-vous ?

Il existe de très nombreux appareils connectés à Internet, et presque tous disposent d'un navigateur. La complication réside dans leur diversité: ordinateurs portables Mac, stations de travail Windows, iPhone, iPad, téléphones Android avec saisie tactile, molettes, claviers, saisie vocale, appareils sensibles à la pression, montres connectées, grille-pain, réfrigérateurs et bien d'autres encore. Certains de ces appareils sont omniprésents, tandis que d'autres sont très rares.

Divers appareils.
Divers appareils (source).

Pour créer une expérience utilisateur de qualité, vous devez savoir qui sont vos utilisateurs et quels appareils ils utilisent. Si vous créez une interface utilisateur pour un utilisateur de bureau avec une souris et un clavier et que vous la fournissez à un utilisateur de smartphone, votre interface sera une frustration, car elle est conçue pour une autre taille d'écran et une autre modalité de saisie.

Il existe deux extrémités extrêmes dans le spectre des approches:

  1. Créez une version qui fonctionne sur tous les appareils. L'expérience utilisateur en sera affectée, car les considérations de conception diffèrent selon les appareils.

  2. Créez une version pour chaque appareil que vous souhaitez prendre en charge. Cela prendra indéfiniment, car vous allez compiler trop de versions de votre application. De plus, lorsque le prochain smartphone arrive (ce qui se produit environ toutes les semaines), vous devrez créer une autre version.

Il s'agit ici d'un compromis fondamental: plus vous avez de catégories d'appareils, meilleure est l'expérience utilisateur, mais plus la conception, l'implémentation et la maintenance sont importantes.

Il peut être judicieux de créer une version distincte pour chaque classe d'appareils que vous choisissez pour des raisons de performances ou si les versions que vous souhaitez diffuser à différentes classes d'appareils varient considérablement. Sinon, le Responsive Web Design est une approche parfaitement raisonnable.

Une solution potentielle

Voici un compromis: classez les appareils en catégories et concevez la meilleure expérience possible pour chaque catégorie. Les catégories que vous choisissez dépendent de votre produit et de l'utilisateur cible. Voici un exemple de classification qui couvre bien les appareils Web populaires existants.

  1. petits écrans + tactile (principalement des téléphones)
  2. grands écrans + écran tactiles (surtout les tablettes)
  3. grands écrans + clavier/souris (principalement les ordinateurs de bureau et portables)

Il ne s'agit là que de l'une des nombreuses répartitions possibles, mais celle-ci a beaucoup de sens au moment de la rédaction de ce document. Les appareils mobiles sans écran tactile ne figurent pas dans la liste ci-dessus (par exemple, les feature phones ou certains lecteurs d'e-books dédiés). Cependant, la plupart d'entre eux disposent d'un logiciel de navigation au clavier ou de lecteur d'écran installé, ce qui fonctionnera bien si vous créez votre site en tenant compte de l'accessibilité.

Exemples d'applications Web spécifiques au facteur de forme

Il existe de nombreux exemples de propriétés Web proposant des versions entièrement différentes pour différents facteurs de forme. C'est ce que fait la recherche Google, comme Facebook. Ces considérations incluent à la fois les performances (extraction des éléments, affichage des pages) et l'expérience utilisateur plus générale.

Dans le monde des applications natives, de nombreux développeurs choisissent d'adapter leur expérience à une classe d'appareils. Par exemple, l'interface utilisateur de Flipboard pour iPad est très différente de celle de Flipboard sur iPhone. La version pour tablette est optimisée pour une utilisation à deux mains et un retournement horizontal, tandis que la version pour téléphone est destinée aux interactions d'une seule main et au retournement vertical. De nombreuses autres applications iOS proposent également des versions très différentes pour téléphone et tablette, telles que Activités (liste de tâches) et Showyou (vidéo sur les réseaux sociaux), présentée ci-dessous:

Personnalisation importante de l'interface utilisateur pour téléphone et tablette.
Personnalisation significative de l'interface utilisateur pour les téléphones et les tablettes

Approche n° 1: détection côté serveur

Sur le serveur, nous avons une compréhension beaucoup plus limitée de l'appareil dont nous avons affaire. L'indice le plus utile disponible est probablement la chaîne user-agent, fournie via l'en-tête user-agent à chaque requête. De ce fait, la même approche de détection UA fonctionne ici. En fait, les projets DeviceAtlas et WURFL le font déjà (et fournissent de nombreuses informations supplémentaires sur l'appareil).

Malheureusement, chacun d'entre eux présente ses propres défis. WURFL est très volumineux et contient 20 Mo de XML, ce qui peut entraîner une surcharge importante côté serveur pour chaque requête. Certains projets divisent le code XML pour des raisons de performances. DeviceAtlas n'est pas Open Source et nécessite une licence payante pour l'utiliser.

Il existe également des alternatives plus simples et sans frais, telles que le projet Detect Mobile Browsers (Détecter les navigateurs mobiles). L'inconvénient, bien sûr, est que la détection des appareils sera inévitablement moins complète. De plus, il ne fait la distinction qu'entre les appareils mobiles et non mobiles, et ne permet donc de bénéficier d'une compatibilité limitée avec les tablettes qu'avec un ensemble d'ajustements ad hoc.

Approche n° 2: détection côté client

La détection des fonctionnalités nous permet d'en apprendre beaucoup sur le navigateur et l'appareil de l'utilisateur. Les principaux éléments que nous devons déterminer sont si l'appareil est doté d'une fonctionnalité tactile et s'il s'agit d'un petit ou d'un grand écran.

Nous devons fixer une ligne pour distinguer les appareils tactiles petits et grands. Qu'en est-il des coques spéciales telles que le Galaxy Note 5 pouces ? Le graphique suivant montre un grand nombre d'appareils Android et iOS courants superposés (avec les résolutions d'écran correspondantes). L'astérisque indique que l'appareil est disponible ou peut présenter une densité doublée. Même si la densité en pixels peut être doublée, le CSS signale toujours les mêmes tailles.

Petite remarque concernant les pixels en CSS: les pixels CSS sur le Web mobile ne sont pas les mêmes que les pixels d'écran. Les appareils iOS Retina ont introduit la pratique de doubler la densité de pixels (par exemple, iPhone 3GS contre 4, iPad 2 plutôt que 3). Les UA Retina Mobile Safari continuent de signaler la même largeur d'appareil pour éviter d'endommager le Web. Comme les autres appareils (par exemple, Android) obtiennent des écrans de meilleure résolution, ils font la même chose pour la largeur de l'appareil.

Résolution de l'appareil (en pixels).
Résolution de l'appareil (en pixels).

Toutefois, pour compliquer cette décision, il est important de prendre en compte à la fois les modes Portrait et Paysage. Nous ne voulons pas actualiser la page ni charger de scripts supplémentaires chaque fois que nous réorientons l'appareil, même si nous souhaitons afficher la page différemment.

Dans le schéma suivant, les carrés représentent les dimensions maximales de chaque appareil, en raison de la superposition des contours des modes portrait et paysage (et de compléter le carré):

Résolution portrait et paysage (en pixels)
Résolution portrait et paysage (en pixels)

Si le seuil est défini sur 650px, nous classons l'iPhone et le Galaxy Nexus dans la catégorie "smalltouch", et l'iPad et le Galaxy Tab dans la catégorie "tablette". La Galaxy Note, androgyne, est ici classée dans la catégorie "téléphone" et obtiendra la disposition du téléphone.

Voici une stratégie raisonnable:

if (hasTouch) {
  if (isSmall) {
    device = PHONE;
  } else {
    device = TABLET;
  }
} else {
  device = DESKTOP;
}

Voir un exemple minimal de l'approche de détection de caractéristiques en action.

L'autre approche consiste à utiliser le reniflage d'UA pour détecter le type d'appareil. En gros, vous créez un ensemble d'heuristiques et les faites correspondre au navigator.userAgent de votre utilisateur. Le pseudo-code ressemble à ceci:

var ua = navigator.userAgent;
for (var re in RULES) {
  if (ua.match(re)) {
    device = RULES[re];
    return;
  }
}

Découvrez un exemple de l'approche de détection UA en action.

Remarque sur le chargement côté client

Si vous effectuez une détection UA sur votre serveur, vous pouvez choisir les fichiers CSS, JavaScript et DOM à diffuser lorsque vous recevez une nouvelle requête. Toutefois, si vous effectuez une détection côté client, la situation est plus complexe. Plusieurs options s'offrent à vous:

  1. Redirigez les utilisateurs vers une URL spécifique au type d'appareil contenant la version de ce type d'appareil.
  2. Chargez dynamiquement les composants spécifiques au type d'appareil.

La première approche est simple et nécessite une redirection telle que window.location.href = '/tablet'. Toutefois, ces informations sur le type d'appareil sont désormais ajoutées à l'emplacement. Vous pouvez donc utiliser l'API History pour nettoyer votre URL. Malheureusement, cette approche implique une redirection, qui peut être lente, en particulier sur les appareils mobiles.

La deuxième approche est un peu plus complexe à mettre en œuvre. Vous avez besoin d'un mécanisme pour charger dynamiquement les CSS et JavaScript. (selon le navigateur), vous ne pourrez peut-être pas personnaliser <meta viewport>. De plus, comme il n'y a pas de redirection, vous pouvez rester bloqué avec le code HTML d'origine qui a été diffusé. Vous pouvez bien sûr le manipuler avec JavaScript, mais cette opération peut s'avérer lente et/ou inutile, en fonction de votre application.

Choix du client ou du serveur

Voici les compromis entre ces approches:

Client Pro :

  • Solution davantage évolutive car basée sur les tailles/fonctionnalités d'écran plutôt que sur UA.
  • Il n'est pas nécessaire de mettre à jour constamment la liste UA.

Serveur Pro :

  • Contrôle total de la version à diffuser sur chaque appareil.
  • Performances améliorées: plus besoin de redirections client ni de chargement dynamique.

Ma préférence personnelle consiste à commencer avec device.js et la détection côté client. À mesure que votre application évolue, si vous estimez que la redirection côté client représente un inconvénient en termes de performances, vous pouvez facilement supprimer le script device.js et mettre en œuvre la détection UA sur le serveur.

Présentation de device.js

Device.js est un point de départ pour effectuer une détection sémantique d'appareil basée sur les requêtes multimédias, sans nécessiter de configuration spéciale côté serveur, ce qui permet d'économiser le temps et les efforts nécessaires pour analyser les chaînes user-agent.

L'idée est de fournir un balisage compatible avec les moteurs de recherche (link rel=alternate) en haut de votre fichier <head>, pour indiquer les versions de votre site que vous souhaitez fournir.

<link rel="alternate" href="http://foo.com" id="desktop"
    media="only screen and (touch-enabled: 0)">

Vous pouvez ensuite effectuer une détection UA côté serveur et gérer vous-même la redirection de version, ou utiliser le script device.js pour effectuer une redirection côté client basée sur les fonctionnalités.

Pour en savoir plus, consultez la page du projet device.js, ainsi que l'application fictive qui utilise device.js pour la redirection côté client.

Recommandation: MVC avec des vues spécifiques au facteur de forme

À présent, vous pensez probablement que je vous demande de créer trois applications complètement distinctes, une pour chaque type d'appareil. Non ! Le partage de code est la clé.

J'espère que vous avez utilisé un framework de type MVC, tel que Backbone, Ember, etc. Si vous l'avez déjà lu, vous connaissez le principe de séparation des tâches, en particulier le fait que votre UI (couche de vue) doit être découplée de votre logique (couche de modèle). Si vous débutez, commencez par utiliser certaines de ces ressources sur MVC et MVC en JavaScript.

L'analyse multi-appareil s'intègre parfaitement dans votre framework MVC existant. Vous pouvez facilement déplacer vos vues dans des fichiers distincts, en créant une vue personnalisée pour chaque type d'appareil. Vous pouvez ensuite diffuser le même code sur tous les appareils, sauf la couche de vue.

MVC multi-appareil.
MVC inter-appareil

Votre projet peut présenter la structure suivante (évidemment, vous êtes libre de choisir celle qui convient le mieux en fonction de votre application):

model.js item-collection.js (modèles partagés)

contrôleurs/ (contrôleurs partagés) item-controller.js

versions/ (éléments propres à l'appareil) tablette/ordinateur/téléphone/ (code spécifique au téléphone) style.css index.html views/item.js item-list.js

Ce type de structure vous permet de contrôler entièrement les éléments chargés par chaque version, car vous disposez de code HTML, CSS et JavaScript personnalisé pour chaque appareil. Cette approche très efficace peut constituer la méthode de développement la plus légère et la plus performante pour le Web multi-appareil, sans passer par des techniques telles que les images adaptatives.

Après avoir exécuté votre outil de compilation préféré, vous allez concaténer et réduire la taille de votre code JavaScript et CSS en fichiers uniques pour un chargement plus rapide, avec un code HTML de production semblable à celui-ci (pour un téléphone, avec 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>

Notez que la requête média (touch-enabled: 0) n'est pas standard (implémentée dans Firefox uniquement avec le préfixe de fournisseur moz), mais elle est gérée correctement (grâce à Modernizr.touch) par device.js.

Remplacement de version

La détection de l'appareil peut parfois se tromper, et dans certains cas, un utilisateur peut préférer consulter la disposition de la tablette sur son téléphone (par exemple, il utilise un Galaxy Note). Il est donc important de donner aux utilisateurs le choix de la version de votre site à utiliser s'ils souhaitent la remplacer manuellement.

L'approche habituelle consiste à fournir un lien vers la version classique à partir de votre version mobile. Cette fonctionnalité est suffisamment facile à implémenter, mais device.js prend en charge cette fonctionnalité avec le paramètre GET device.

Conclusion

En résumé, lorsque vous créez des interfaces utilisateur multi-appareils monopages, qui ne correspondent pas parfaitement au monde du responsive design, procédez comme suit:

  1. Choisissez un ensemble de classes d'appareils compatibles et les critères de classification des appareils.
  2. Créez votre application MVC en veillant à ce que les tâches soient parfaitement séparées en divisant les vues du reste du codebase.
  3. Utiliser device.js pour détecter les classes d'appareils côté client.
  4. Lorsque vous êtes prêt, empaquetez le script et les feuilles de style dans l'une ou l'autre pour chaque classe d'appareil.
  5. Si les performances de redirection côté client posent problème, abandonnez device.js et passez à la détection UA côté serveur.