Une approche non responsive pour créer des applications Web multi-appareils

Les requêtes multimédias sont utiles, mais…

Les requêtes multimédias sont géniales, une aubaine pour les développeurs de sites Web qui souhaitent apporter de petits ajustements à leurs feuilles de style afin d'offrir une meilleure expérience aux 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 multimédias sur mediaqueri.es.

Comme Brad Frost le souligne dans un article précédent, modifier l'apparence n'est qu'un des nombreux éléments à prendre en compte lors de la création pour le Web mobile. Si la seule chose que vous faites lorsque vous créez votre site Web mobile est de personnaliser votre mise en page avec des requêtes multimédias, la situation est la suivante:

  • Tous les appareils reçoivent le même code JavaScript, CSS et les mêmes composants (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 forcer les développeurs à écrire du CSS trop compliqué.
  • Peu de flexibilité pour spécifier des interactions personnalisées adaptées à chaque appareil.

Les applications Web ont besoin de plus que de requêtes multimédias

Ne vous méprenez pas. Je n'ai pas de problème avec le responsive design via les requêtes multimédias et je pense qu'il a sa place dans le monde. De plus, certains des problèmes mentionnés ci-dessus peuvent être résolus à l'aide d'approches telles que les images responsives, le chargement de script dynamique, etc. Toutefois, à un moment donné, vous risquez de faire trop de modifications incrémentielles et il peut être préférable de diffuser différentes versions.

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

Quelles classes d'appareils ciblez-vous ?

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

Divers appareils.
Différents appareils (source).

Pour créer une bonne expérience utilisateur, 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 donnez à un utilisateur de smartphone, votre interface sera frustrante, car elle est conçue pour une autre taille d'écran et une autre modalité d'entrée.

Le spectre des approches se situe entre deux extrêmes:

  1. Créez une version qui fonctionne sur tous les appareils. L'expérience utilisateur en souffrira, car les différents appareils ont des considérations de conception différentes.

  2. Créez une version pour chaque appareil que vous souhaitez prendre en charge. Cela prendra une éternité, car vous créerez trop de versions de votre application. De plus, lorsque le prochain nouveau smartphone arrivera (ce qui se produit environ une fois par semaine), vous serez obligé de créer une autre version.

Il existe un compromis fondamental: plus vous avez de catégories d'appareils, meilleure est l'expérience utilisateur que vous pouvez offrir, mais plus le travail de conception, d'implémentation et de maintenance sera important.

Créer une version distincte pour chaque classe d'appareil que vous choisissez peut être une bonne idée pour des raisons de performances ou si les versions que vous souhaitez diffuser auprès de différentes classes d'appareils varient considérablement. Sinon, le responsive web design est une approche tout à fait raisonnable.

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 votre utilisateur cible. Voici un exemple de classification qui couvre bien les appareils Web populaires existants.

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

Il ne s'agit là que d'une des nombreuses répartitions possibles, mais elle semble très pertinente au moment de la rédaction de cet article. Les appareils mobiles sans écran tactile (par exemple, les téléphones standards et certains lecteurs de livres électroniques dédiés) ne figurent pas dans la liste ci-dessus. Toutefois, la plupart d'entre eux disposent d'un logiciel de navigation au clavier ou de lecteur d'écran, qui fonctionnera parfaitement si vous concevez 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 diffusant des versions entièrement différentes pour différents facteurs de forme. La recherche Google et Facebook le font. Cela concerne à la fois les performances (récupération des éléments, rendu 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 basculement horizontal, tandis que la version pour téléphone est conçue pour une interaction à une main et un basculement vertical. De nombreuses autres applications iOS proposent également des versions pour téléphone et tablette très différentes, comme Things (liste de tâches) et Showyou (vidéo sur les réseaux sociaux), présentées ci-dessous:

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

Approche 1: Détection côté serveur

Sur le serveur, nous avons une compréhension beaucoup plus limitée de l'appareil avec lequel nous travaillons. L'indice le plus utile disponible est probablement la chaîne user-agent, qui est fournie via l'en-tête User-Agent pour chaque requête. Par conséquent, la même approche d'analyse de la balise UA fonctionnera ici. En fait, les projets DeviceAtlas et WURFL le font déjà (et fournissent de nombreuses informations supplémentaires sur l'appareil).

Malheureusement, chacune de ces options présente ses propres défis. WURFL est très volumineux, contenant 20 Mo de code XML, ce qui peut entraîner des coûts importants côté serveur pour chaque requête. Certains projets divisent le fichier XML pour des raisons de performances. DeviceAtlas n'est pas Open Source et nécessite une licence payante pour être utilisé.

Il existe également des alternatives plus simples et sans frais, comme 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 que entre les appareils mobiles et non mobiles, et ne prend en charge les tablettes que de manière limitée via un ensemble de modifications ponctuelles.

Méthode 2: Détection côté client

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

Nous devons tracer la ligne quelque part pour distinguer les petits et les grands appareils tactiles. Qu'en est-il des cas particuliers comme le Galaxy Note 5 pouces ? Le graphique suivant montre un certain nombre d'appareils Android et iOS populaires superposés (avec les résolutions d'écran correspondantes). L'astérisque indique que l'appareil est disponible ou peut être disponible avec une densité doublée. Bien que la densité de pixels puisse être doublée, le CSS indique toujours les mêmes tailles.

Remarque rapide sur les pixels en CSS: les pixels CSS sur le Web mobile ne sont pas les mêmes que les pixels de l'écran. Les appareils iOS Retina ont introduit la pratique consistant à doubler la densité de pixels (par exemple, iPhone 3GS par rapport à l'iPhone 4, iPad 2 par rapport à l'iPad 3). Les UA Safari mobile Retina indiquent toujours la même largeur d'appareil pour éviter de casser le Web. Comme d'autres appareils (par exemple, Android) disposent d'écrans haute résolution, ils utilisent le même tour de passe-passe avec la largeur de l'appareil.

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

Cependant, cette décision est compliquée par le fait qu'il est important de tenir compte des 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 pouvons souhaiter afficher la page différemment.

Dans le diagramme suivant, les carrés représentent les dimensions maximales de chaque appareil, obtenues en superposant les contours en mode portrait et paysage (et en complétant le carré):

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

En définissant le seuil sur 650px, nous classons l'iPhone et le Galaxy Nexus comme "petit écran tactile", et l'iPad et la Galaxy Tab comme "tablette". Dans ce cas, le Galaxy Note androgyne est classé comme "téléphone" et reçoit la mise en page pour téléphone.

Une stratégie raisonnable pourrait donc se présenter comme suit:

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

Découvrez un exemple minimal de l'approche de détection des caractéristiques en action.

L'approche alternative consiste à utiliser l'analyse de l'UA pour détecter le type d'appareil. En gros, vous créez un ensemble d'heuristiques et les mettez en correspondance avec l'navigator.userAgent de votre utilisateur. Le pseudo-code se présente comme suit:

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 des UA.

Remarque concernant le chargement côté client

Si vous effectuez une détection UA sur votre serveur, vous pouvez décider du CSS, du JavaScript et du 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 vers une URL spécifique au type d'appareil qui contient la version pour 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 seront désormais ajoutées à la position. 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 beaucoup plus complexe à mettre en œuvre. Vous avez besoin d'un mécanisme pour charger dynamiquement CSS et JS. En fonction du navigateur, vous ne pourrez peut-être pas effectuer des actions telles que personnaliser <meta viewport>. De plus, comme il n'y a pas de redirection, vous êtes bloqué avec le code HTML d'origine qui a été diffusé. Bien sûr, vous pouvez le manipuler avec JavaScript, mais cela peut être lent et/ou peu élégant, selon votre application.

Décider si le client ou le serveur

Voici les compromis entre les deux approches:

Client Pro:

  • Plus évolutif, car basé sur les tailles/fonctionnalités d'écran plutôt que sur UA.
  • Vous n'avez pas besoin de mettre à jour constamment la liste des UA.

Serveur Pro:

  • Contrôle total de la version à diffuser sur les appareils.
  • Meilleures performances: pas besoin de redirections client ni de chargement dynamique.

Personnellement, je préfère commencer par device.js et la détection côté client. À mesure que votre application évolue, si vous constatez que la redirection côté client est un inconvénient important en termes de performances, vous pouvez facilement supprimer le script device.js et implémenter la détection de l'UA sur le serveur.

Présentation de device.js

Device.js est un point de départ pour effectuer une détection sémantique basée sur des requêtes multimédias sans avoir besoin d'une configuration côté serveur spéciale, ce qui permet de gagner du temps et de l'effort pour analyser la chaîne de l'user-agent.

L'idée est de fournir un balisage adapté aux moteurs de recherche (link rel=alternate) en haut de votre <head>, indiquant 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)">

Ensuite, vous pouvez effectuer la détection de l'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 qu'une fausse application qui utilise device.js pour la redirection côté client.

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

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é.

Nous espérons que vous avez utilisé un framework de type MVC, tel que Backbone, Ember, etc. Si c'est le cas, vous connaissez le principe de séparation des responsabilités, en particulier que votre UI (couche de vue) doit être dissociée de votre logique (couche de modèle). Si vous ne connaissez pas ce concept, commencez par consulter certaines de ces ressources sur MVC et sur le MVC en JavaScript.

L'histoire multi-appareils s'intègre parfaitement à 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, à l'exception de la couche de vue.

MVC multi-appareil
MVC multi-appareils.

Votre projet peut avoir la structure suivante (bien entendu, vous êtes libre de choisir la structure la plus adaptée en fonction de votre application):

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

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

versions/ (éléments spécifiques à l'appareil) tablet/ desktop/ 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 que chaque version charge, car vous disposez de code HTML, CSS et JavaScript personnalisés pour chaque appareil. Cette approche est très puissante et peut conduire à la méthode de développement la plus simple et la plus performante pour le Web multi-appareils, sans avoir à recourir à des astuces telles que les images adaptatives.

Une fois que vous avez exécuté votre outil de compilation préféré, vous concatenatez et minifiez l'ensemble de votre code JavaScript et CSS dans des fichiers uniques pour accélérer le chargement. Votre code HTML de production ressemble à ceci (pour un téléphone, en utilisant 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 multimédia (touch-enabled: 0) n'est pas standard (implémentée uniquement dans Firefox derrière un préfixe de fournisseur moz), mais qu'elle est gérée correctement (grâce à Modernizr.touch) par device.js.

Remplacement de la version

La détection d'appareil peut parfois échouer. Dans certains cas, un utilisateur peut préférer consulter la mise en page de la tablette sur son téléphone (il utilise peut-être un Galaxy Note). Il est donc important de laisser à vos 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 depuis la version mobile. Cette fonctionnalité est assez facile à implémenter, mais device.js la prend en charge avec le paramètre GET device.

Conclusion

Pour résumer, lorsque vous créez des UI monopages multi-appareils qui ne s'intègrent pas parfaitement au monde du responsive design, procédez comme suit:

  1. Choisissez un ensemble de classes d'appareils à prendre en charge et les critères de classification des appareils en classes.
  2. Créez votre application MVC avec une forte séparation des responsabilités, en séparant les vues du reste du codebase.
  3. Utilisez device.js pour effectuer la détection de la classe d'appareil côté client.
  4. Lorsque vous êtes prêt, empaquetez votre script et vos feuilles de style dans un fichier 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.