Les requêtes média sont très utiles, mais…
Les requêtes média sont géniales et constituent une aubaine pour les développeurs de sites Web qui souhaitent apporter de petites modifications à 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 des requêtes média sur mediaqueri.es.
Comme le souligne Brad Frost dans un article précédent, la modification de 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 média, vous vous trouvez dans la situation suivante :
- Tous les appareils reçoivent les mêmes fichiers JavaScript, CSS et 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 obliger les développeurs à écrire du CSS trop complexe.
- Peu de flexibilité pour spécifier des interactions personnalisées adaptées à chaque appareil.
Les applications Web ont besoin de 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 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 dynamique de scripts, etc. Cependant, à un certain moment, vous pouvez vous retrouver à effectuer trop de modifications incrémentales, et il peut être préférable de diffuser différentes versions.
À mesure que les UI que vous créez deviennent plus complexes et que vous vous orientez vers des applications Web monopages, vous souhaiterez personnaliser davantage les UI 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 de votre visiteur dans la bonne catégorie d'appareil 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 une multitude d'appareils connectés à Internet, et presque tous sont équipés d'un navigateur. La difficulté réside dans leur diversité : ordinateurs portables Mac, postes de travail Windows, iPhones, iPads, téléphones Android avec saisie tactile, molettes, claviers, saisie vocale, appareils avec sensibilité à la pression, montres connectées, grille-pains, réfrigérateurs et bien d'autres encore. Certains de ces appareils sont omniprésents, tandis que d'autres sont très rares.
Pour offrir 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 d'ordinateur de bureau avec une souris et un clavier, puis 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.
Il existe deux approches extrêmes :
Créez une version qui fonctionne sur tous les appareils. L'expérience utilisateur en souffrira, car les considérations de conception varient selon les appareils.
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, lorsqu'un nouveau smartphone sortira (ce qui arrive environ toutes les semaines), vous serez obligé de créer une autre version.
Il existe ici un compromis fondamental : plus vous avez de catégories d'appareils, meilleure sera l'expérience utilisateur que vous pourrez offrir, mais plus il faudra de travail pour concevoir, implémenter et maintenir l'application.
Pour des raisons de performances ou si les versions que vous souhaitez diffuser sur différentes classes d'appareils varient considérablement, il peut être judicieux de créer une version distincte pour chaque classe d'appareils. Sinon, la conception Web responsives est une approche tout à fait raisonnable.
Solution possible
Voici un compromis : classez les appareils dans des 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 aujourd'hui.
- Petits écrans + tactile (principalement les téléphones)
- grands écrans + tactile (principalement les tablettes)
- Grands écrans + clavier/souris (principalement les ordinateurs de bureau/portables)
Il ne s'agit là que d'une répartition possible parmi d'autres, mais qui a beaucoup de sens au moment de la rédaction. Les appareils mobiles sans écran tactile (par exemple, les téléphones classiques et certains lecteurs d'e-books dédiés) ne figurent pas dans la liste ci-dessus. Toutefois, la plupart d'entre eux sont équipés 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 à un facteur de forme
De nombreuses propriétés Web proposent des versions entièrement différentes pour différents facteurs de forme. La recherche Google et Facebook le font. Les considérations à prendre en compte incluent les performances (récupération des composants, 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 catégorie 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 conçue pour une interaction à une main et un retournement 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éos sociales), présentées ci-dessous :
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 traitons. L'indice le plus utile est probablement la chaîne user-agent, qui est fournie via l'en-tête User-Agent de chaque requête. Par conséquent, la même approche d'analyse de l'UA fonctionnera ici. En fait, les projets DeviceAtlas et WURFL le font déjà (et fournissent beaucoup d'informations supplémentaires sur l'appareil).
Malheureusement, chacun de ces éléments présente ses propres difficultés. WURFL est très volumineux (20 Mo de code XML), ce qui peut entraîner un surdébit côté serveur important 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 sans frais plus simples, comme le projet Detect Mobile Browsers. 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 n'offre qu'une compatibilité limitée avec les tablettes grâce à un ensemble de modifications ad hoc.
Approche 2 : Détection côté client
Nous pouvons en apprendre beaucoup sur le navigateur et l'appareil de l'utilisateur en utilisant la détection de fonctionnalités. Les principaux éléments à déterminer sont les suivants : l'appareil est-il tactile ? S'agit-il d'un grand ou d'un petit écran ?
Nous devons établir une limite pour distinguer les petits et les grands appareils tactiles. Qu'en est-il des cas extrêmes comme le Galaxy Note de 5 pouces ? Le graphique suivant montre un ensemble d'appareils Android et iOS populaires superposés (avec les résolutions d'écran correspondantes). L'astérisque indique que l'appareil est ou peut être disponible en double densité. Bien que la densité de pixels puisse être doublée, le CSS indique toujours les mêmes tailles.
Petite parenthèse sur 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 du doublement de la densité de pixels (par exemple, iPhone 3GS vs 4, iPad 2 vs 3). Les UA Mobile Safari Retina signalent toujours la même largeur d'appareil pour éviter de casser le Web. Comme d'autres appareils (par exemple, Android) obtiennent des écrans haute résolution, ils utilisent la même astuce de largeur d'appareil.
Toutefois, il est important de prendre en compte les modes portrait et paysage, ce qui complique cette décision. Nous ne voulons pas recharger la page ni charger de scripts supplémentaires chaque fois que nous réorientons l'appareil, même si nous pouvons vouloir afficher la page différemment.
Dans le schéma suivant, les carrés représentent les dimensions maximales de chaque appareil, après superposition des contours portrait et paysage (et complétion du carré) :
En définissant le seuil sur 650px, nous classons l'iPhone et le Galaxy Nexus comme des appareils "smalltouch", et l'iPad et la Galaxy Tab comme des tablettes. Le Galaxy Note androgyne est classé comme "téléphone" et obtient la mise en page pour téléphone.
Voici une stratégie raisonnable :
if (hasTouch) {
if (isSmall) {
device = PHONE;
} else {
device = TABLET;
}
} else {
device = DESKTOP;
}
Découvrez un exemple minimal de l'approche de détection de fonctionnalités en action.
L'autre approche consiste à utiliser le sniffing de l'agent utilisateur pour détecter le type d'appareil. En gros, vous créez un ensemble d'heuristiques et les comparez aux navigator.userAgent de vos utilisateurs. 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 détection de l'UA en action.
Remarque sur le chargement côté client
Si vous effectuez la détection de l'UA sur votre serveur, vous pouvez décider quel 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 :
- Redirigez l'utilisateur vers une URL spécifique au type d'appareil qui contient la version pour ce type d'appareil.
- 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, les 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 à implémenter. Vous avez besoin d'un mécanisme pour charger dynamiquement le CSS et le JS. De plus, selon le navigateur, vous ne pourrez peut-être pas 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.
Choisir entre le client et le serveur
Voici les compromis entre les approches :
Client Pro :
- Plus pérenne, car basé sur la taille et les capacités de l'écran plutôt que sur l'UA.
- Vous n'avez pas besoin de mettre à jour constamment la liste des UA.
Serveur Pro :
- Contrôle total de la version à diffuser sur chaque appareil.
- 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. Si vous constatez que la redirection côté client est un inconvénient majeur en termes de performances à mesure que votre application évolue, 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 la détection sémantique des appareils basée sur les requêtes média, sans nécessiter de configuration spéciale côté serveur. Cela permet de gagner du temps et d'éviter d'avoir à analyser les chaînes de l'agent utilisateur.
L'idée est de fournir un balisage compatible avec les moteurs de recherche (link
rel=alternate) en haut de votre <head>, en 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
À ce stade, 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 essentiel.
Nous espérons que vous avez utilisé un framework de type MVC, tel que Backbone ou Ember. Si c'est le cas, vous connaissez le principe de séparation des préoccupations, en particulier le fait 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 ces ressources sur MVC et 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 Vue.
Votre projet peut avoir la structure suivante (bien sûr, vous êtes libre de choisir la structure qui a le plus de sens en fonction de votre application) :
models/ (shared models) item.js item-collection.js
controllers/ (shared controllers) 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 chargés par chaque version, car vous disposez de code HTML, CSS et JavaScript personnalisés pour chaque appareil. Cette fonctionnalité est très puissante et peut permettre de développer pour le Web multi-appareils de la manière la plus simple et la plus performante possible, sans avoir recours à des astuces telles que les images adaptatives.
Une fois votre outil de compilation préféré exécuté, vous concaténez et minimisez tous vos fichiers JavaScript et CSS en un seul fichier pour un chargement plus rapide. Votre fichier HTML de production ressemblera à ce qui suit (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 média (touch-enabled: 0) n'est pas standard (elle n'est implémentée que 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 des appareils peut parfois mal fonctionner. Dans certains cas, un utilisateur peut préférer consulter la mise en page pour tablette sur son téléphone (par exemple, s'il utilise un Galaxy Note). Il est donc important de lui donner le choix de la version de votre site à utiliser s'il souhaite la remplacer manuellement.
L'approche habituelle consiste à fournir un lien vers la version pour ordinateur depuis votre version mobile. Cette fonctionnalité est facile à implémenter, mais device.js la prend en charge avec le paramètre GET device.
Conclusion
En résumé, lorsque vous créez des interfaces utilisateur monopages multi-appareils qui ne s'intègrent pas parfaitement dans le monde du design responsif, procédez comme suit :
- Choisissez un ensemble de classes d'appareils à prendre en charge, ainsi que les critères permettant de classer les appareils dans ces classes.
- Créez votre application MVC avec une forte séparation des préoccupations, en divisant les vues du reste du codebase.
- Utilisez device.js pour détecter la classe d'appareil côté client.
- Lorsque vous êtes prêt, regroupez votre script et vos feuilles de style dans un fichier pour chaque classe d'appareil.
- Si les performances de redirection côté client posent problème, abandonnez device.js et passez à la détection de l'UA côté serveur.