Introduction
Le développement pour le Web mobile est un sujet d'actualité. Cette année, pour la première fois, les smartphones ont dépassé les PC en termes de ventes. De plus en plus d'utilisateurs se servent d'un appareil mobile pour naviguer sur le Web. Il devient donc essentiel pour les développeurs d'optimiser leurs sites pour les navigateurs mobiles.
Le champ de bataille "mobile" est encore inexploré pour un grand nombre de développeurs. De nombreuses personnes disposent d'anciens sites qui ne prennent pas du tout en compte les utilisateurs mobiles. En revanche, le site a été conçu principalement pour la navigation sur ordinateur et se dégrade dans les navigateurs mobiles. Ce site (html5rocks.com) ne fait pas exception. Lors du lancement, nous avons peu d'efforts pour créer une version mobile du site.
Créer un site html5rocks.com adapté aux mobiles
Pour m'entraîner, j'ai pensé qu'il serait intéressant de prendre html5rocks (un site HTML5 existant) et de l'enrichir d'une version adaptée aux mobiles. Je me préoccupais principalement de la quantité minimale de travail requise pour cibler les smartphones. L'objectif de mon exercice n'était pas de créer un site mobile entièrement nouveau et de gérer deux bases de code. Cela aurait pris une éternité et aurait été un énorme gaspillage de temps. Nous avons déjà défini la structure du site (balisage). Nous avons examiné l'apparence (CSS). La fonctionnalité de base (JS) était là. Le fait est que de nombreux sites se trouvent dans la même situation.
Cet article explique comment nous avons créé une version mobile de html5rocks optimisée pour les appareils Android et iOS. Il vous suffit de charger html5rocks.com sur un appareil compatible avec l'un de ces systèmes d'exploitation pour voir la différence. Il n'y a aucune redirection vers m.html5rocks.com ni autre bêtise de cette nature. Vous bénéficiez de html5rocks tel quel, avec l'avantage supplémentaire d'un élément qui s'affiche et fonctionne bien sur un appareil mobile.
Requêtes multimédias CSS
HTML4 et CSS2 sont compatibles avec les feuilles de style dépendantes des supports depuis un certain temps. Exemple :
<link rel="stylesheet" media="print" href="printer.css">
ciblerait les appareils d'impression et fournirait un style spécifique au contenu de la page lorsqu'il est imprimé. Le CSS3 va plus loin dans l'idée des types de médias et améliore leur fonctionnalité avec les requêtes multimédias. Les requêtes média étendent l'utilité des types de médias en permettant un libellé plus précis des feuilles de style. Vous pouvez ainsi personnaliser la présentation du contenu en fonction d'une gamme spécifique d'appareils de sortie sans avoir à modifier le contenu lui-même. Parfait pour une mise en page existante qui doit être modifiée !
Vous pouvez utiliser des requêtes multimédias dans l'attribut media
de vos feuilles de style externes pour cibler la largeur de l'écran, la largeur de l'appareil, l'orientation, etc. Pour obtenir la liste complète, consultez la spécification des requêtes multimédias du W3C.
Cibler les tailles d'écran
Dans l'exemple suivant, phone.css
s'applique aux appareils que le navigateur considère comme "portables" ou aux appareils dont la largeur est inférieure ou égale à 320 pixels.
<link rel='stylesheet'
media='handheld, only screen and (max-device-width: 320px)' href='phone.css'>
Si vous ajoutez le mot clé "only
" comme préfixe à une requête multimédia, les navigateurs non compatibles avec CSS3 ignoreront la règle.
Le code suivant cible les tailles d'écran comprises entre 641 px et 800 px :
<link rel='stylesheet'
media='only screen and (min-width: 641px) and (max-width: 800px)' href='ipad.css'>
Les requêtes média peuvent également apparaître dans les balises <style>
intégrées. Le code suivant cible les types de contenus multimédias all
en mode portrait :
<style>
@media only all and (orientation: portrait) { ... }
</style>
media="handheld"
Nous devons nous arrêter une minute et discuter de media="handheld"
.
En réalité, Android et iOS ignorent media="handheld"
. L'argument est que les utilisateurs manqueront le contenu haut de gamme fourni par les feuilles de style ciblant media="screen"
et que les développeurs sont moins susceptibles de gérer une version media="handheld"
de moindre qualité. Ainsi, dans le cadre de leur devise "Web complet", la plupart des navigateurs pour smartphones modernes ignorent simplement les feuilles de style portables.
Il est idéal d'utiliser cette fonctionnalité pour cibler les appareils mobiles, mais différents navigateurs l'ont implémentée de différentes manières:
- Certains ne lisent que la feuille de style pour appareil mobile.
- Certains ne lisent que la feuille de style pour appareil portable, le cas échéant, mais utilisent par défaut la feuille de style pour écran.
- Certains lisent à la fois la feuille de style pour appareil mobile et la feuille de style pour écran.
- Certains ne lisent que la feuille de style de l'écran.
Opera Mini n'ignore pas media="handheld"
. Pour que Windows Mobile reconnaisse media="handheld"
, vous devez mettre en majuscule la valeur de l'attribut multimédia pour la feuille de style de l'écran :
<!-- media="handheld" trick for Windows Mobile -->
<link rel="stylesheet" href="screen.css" media="Screen">
<link rel="stylesheet" href="mobile.css" media="handheld">
Comment html5rocks utilise les requêtes multimédias
Les requêtes multimédias sont largement utilisées dans html5rocks pour mobile. Ils nous ont permis d'ajuster la mise en page sans avoir à apporter de modifications importantes à la balise de modèle Django. Un vrai sauvetage ! De plus, son assistance est plutôt bonne dans les différents navigateurs.
Dans le fichier <head>
de chaque page, vous trouverez les feuilles de style suivantes:
<link rel='stylesheet'
media='all' href='/static/css/base.min.css' />
<link rel='stylesheet'
media='only screen and (max-width: 800px)' href='/static/css/mobile.min.css' />
base.css
a toujours défini l'apparence principale de html5rocks.com, mais nous appliquons désormais de nouveaux styles (mobile.css
) pour les largeurs d'écran inférieures à 800 px. Sa requête multimédia couvre les téléphones intelligents (environ 320 pixels) et l'iPad (environ 768 pixels).
Effet : nous remplaçons progressivement les styles dans base.css
(uniquement si nécessaire) pour améliorer l'affichage sur mobile.
Voici quelques-unes des modifications de style appliquées par mobile.css
:
- Réduit les espaces blancs/marges intérieures supplémentaires sur le site. Avec un petit écran, l'espace est limité !
- Supprime les états
:hover
. Elles ne s'affichent jamais sur les appareils tactiles. - Ajuste la mise en page pour qu'elle soit en une seule colonne. Nous reviendrons sur ce point.
- Supprime l'
box-shadow
autour de la div du conteneur principal du site. Les ombres de boîtes de grande taille réduisent les performances de la page. - Utilisation du modèle de boîtes CSS flexibles
box-ordinal-group
pour modifier l'ordre de chaque section sur la page d'accueil. Vous remarquerez que la mention "APPRENDRE PAR GROUPES DE FONCTIONNALITÉS HTML5 MAJEURS" apparaît avant la section "TUTORIELS" sur la page d'accueil, mais après dans la version mobile. Cet ordre était plus logique pour les mobiles et ne nécessitait pas de modifier le balisage. Flexbox CSS FTW ! - Supprime les modifications
opacity
. Modifier les valeurs alpha entraîne une baisse des performances sur mobile.
Balises Meta pour mobile
Mobile WebKit est compatible avec quelques fonctionnalités qui offrent aux utilisateurs une meilleure expérience de navigation sur certains appareils.
Paramètres de la fenêtre d'affichage
Le premier paramètre méta (et celui que vous utiliserez le plus souvent) est la propriété "viewport". Définir une fenêtre d'affichage indique au navigateur comment le contenu doit s'adapter à l'écran de l'appareil et informe le navigateur que le site est optimisé pour les mobiles. Exemple :
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
indique au navigateur de définir la fenêtre d'affichage sur la largeur de l'appareil avec une échelle initiale de 1. Cet exemple permet également d'effectuer un zoom, ce qui peut être souhaitable pour un site Web, mais pas pour une application Web. Nous pouvons empêcher le zoom avec user-scalable=no
ou limiter la mise à l'échelle à un certain niveau:
<meta name=viewport
content="width=device-width, initial-scale=1.0, minimum-scale=0.5 maximum-scale=1.0">
Android étend la balise meta viewport en permettant aux développeurs de spécifier la résolution d'écran pour laquelle le site a été développé :
<meta name="viewport" content="target-densitydpi=device-dpi">
Les valeurs possibles pour target-densitydpi
sont device-dpi
, high-dpi
, medium-dpi
et low-dpi
.
Si vous souhaitez modifier votre page Web pour différentes densités d'écran, utilisez la requête média CSS -webkit-device-pixel-ratio
et/ou la propriété window.devicePixelRatio
en JavaScript, puis définissez la méta-propriété target-densitydpi
sur device-dpi
. Cela empêche Android d'effectuer la mise à l'échelle de votre page Web et vous permet d'apporter les ajustements nécessaires pour chaque densité, via CSS et JavaScript.
Pour en savoir plus sur le ciblage des résolutions d'appareil, consultez la documentation WebView d'Android.
Parcourir le Web en plein écran
Il existe deux autres valeurs méta spécifiques à iOS. apple-mobile-web-app-capable
et apple-mobile-web-app-status-bar-style
affichent le contenu de la page en mode plein écran semblable à une application et rendent la barre d'état transparente:
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
Pour en savoir plus sur toutes les méta-options disponibles, consultez la documentation de référence Safari.
Icônes de l'écran d'accueil
Les appareils iOS et Android acceptent également rel="apple-touch-icon"
(iOS) et rel="apple-touch-icon-precomposed"
(Android) pour les liens. Ces éléments créent une icône clignotante ressemblant à une application sur l'écran d'accueil de l'utilisateur lorsqu'il ajoute votre site à ses favoris:
<link rel="apple-touch-icon"
href="/static/images/identity/HTML5_Badge_64.png" />
<link rel="apple-touch-icon-precomposed"
href="/static/images/identity/HTML5_Badge_64.png" />
Comment html5rocks utilise les balises méta pour les mobiles
En résumé, voici un extrait de la section <head>
de html5rocks :
<head>
...
<meta name="viewport"
content="width=device-width, initial-scale=1.0, minimum-scale=1.0" />
<link rel="apple-touch-icon"
href="/static/images/identity/HTML5_Badge_64.png" />
<link rel="apple-touch-icon-precomposed"
href="/static/images/identity/HTML5_Badge_64.png" />
...
</head>
Mise en page verticale
Sur les petits écrans, il est beaucoup plus pratique de faire défiler l'écran verticalement que horizontalement. Pour les mobiles, il est préférable de conserver le contenu dans une mise en page verticale en une seule colonne. Pour html5rocks, nous avons utilisé des requêtes média CSS3 afin de créer une telle mise en page. Là encore, sans modifier le balisage.
Optimisations pour les mobiles
La plupart des optimisations que nous avons effectuées sont des choses qui auraient dû être faites en premier lieu. Par exemple, réduire le nombre de requêtes réseau, compresser les fichiers JS/CSS, gzipper (disponible gratuitement sur App Engine) et minimiser les manipulations DOM. Ces techniques sont des bonnes pratiques courantes, mais elles sont parfois négligées lorsque vous lancez un site rapidement.
Masquer automatiquement la barre d'adresse
Les navigateurs mobiles ne disposent pas de l'espace disponible sur l'écran de leurs homologues pour ordinateur. Pour pirer les choses, sur différentes plates-formes, vous vous retrouvez parfois avec une grande barre d'adresse en haut de l'écran... même une fois le chargement de la page terminé.
Une méthode simple consiste à faire défiler la page à l'aide de JavaScript.
Même si vous ne le faites que d'un seul pixel, la barre d'adresse ennuyeuse disparaîtra.
Pour forcer le masquage de la barre d'adresse sur html5rocks, j'ai associé un gestionnaire d'événements onload
à l'objet window
et fait défiler la page verticalement d'un pixel :
// Hides mobile browser's address bar when page is done loading.
window.addEventListener('load', function(e) {
setTimeout(function() { window.scrollTo(0, 1); }, 1);
}, false);
Nous avons également encapsulé cet écouteur dans notre variable de modèle is_mobile
, car il n'est pas nécessaire sur l'ordinateur.
Réduire les requêtes réseau, économiser de la bande passante
Il est bien connu que réduire le nombre de requêtes HTTP peut considérablement améliorer les performances. Les appareils mobiles limitent encore davantage le nombre de connexions simultanées que le navigateur peut établir. Les sites mobiles bénéficieront donc encore plus de la réduction de ces requêtes superflues. De plus, il est essentiel de réduire chaque octet, car la bande passante est souvent limitée sur les téléphones. Vous risquez de faire perdre de l'argent aux utilisateurs !
Voici quelques-unes des approches que nous avons adoptées pour minimiser les requêtes réseau et réduire la bande passante sur les html5rocks:
Supprimez les iFrames, car elles sont lentes. Une grande partie de notre latence provenait des widgets de partage tiers (Buzz, Google Friend Connect, Twitter, Facebook) sur les pages de tutoriel. Ces API ont été incluses via des balises
<script>
et créent des iFrames qui réduisent la vitesse de la page. Les widgets ont été supprimés pour les appareils mobiles.display:none
: dans certains cas, le balisage était masqué s'il ne convenait pas au profil mobile. Les quatre cases arrondies en haut de la page d'accueil en sont un bon exemple :
Ils ne figurent pas sur le site mobile. Il est important de se rappeler que le navigateur envoie toujours une requête pour chaque icône, même si leur conteneur est masqué par display:none
. Il n'a donc pas suffi de masquer simplement ces boutons. Cela gaspillerait non seulement de la bande passante, mais l'utilisateur ne verrait même pas les fruits de ce gaspillage. La solution a consisté à créer une valeur booléenne "is_mobile" dans notre modèle Django pour omettre de manière conditionnelle des sections de code HTML.
Lorsque l'utilisateur consulte le site sur un appareil connecté, les boutons ne sont pas affichés.
Cache d'application : il permet non seulement de prendre en charge le mode hors connexion, mais aussi de démarrer plus rapidement.
Compression CSS/JS : nous utilisons le compresseur YUI au lieu du compilateur Closure, principalement parce qu'il gère à la fois le CSS et le JS. Nous avons rencontré un problème avec les requêtes multimédias intégrées (requêtes multimédias qui apparaissent dans une feuille de style) dans le compresseur YUI 2.4.2 (voir ce problème). Le problème a été résolu en utilisant YUI Compressor 2.4.4 ou version ultérieure.
Utilisation de sprites CSS lorsque cela est possible
Utilisation de pngcrush pour la compression des images.
Utilisation d'URI de données pour les petites images L'encodage Base64 ajoute environ 30 % de taille à l'image, mais économise la requête réseau.
Chargement automatique de la recherche personnalisée Google à l'aide d'une seule balise de script au lieu de la charger de manière dynamique avec
google.load()
. Ce dernier envoie une requête supplémentaire.
<script src="//www.google.com/jsapi?autoload={"modules":[{"name":"search","version":"1"}]}"> </script>
- Notre imprimante de code et Modernizr étaient inclus sur chaque page, même s'ils n'étaient jamais utilisés. Modernizr est excellent, mais il exécute un tas de tests à chaque chargement. Certains de ces tests apportent des modifications coûteuses au DOM et ralentissent le chargement de la page. Désormais, nous n'incluons ces bibliothèques que sur les pages où elles sont réellement nécessaires. -2 requêtes :)
Autres ajustements des performances:
- Tous les éléments JavaScript ont été déplacés vers le bas de la page (dans la mesure du possible).
- Suppression des balises
<style>
intégrées. - Recherches DOM mises en cache et manipulations DOM minimisées : chaque fois que vous touchez le DOM, le navigateur effectue un reflow. Les reflows sont encore plus coûteux sur un appareil mobile.
- Déchargement du code côté client inutile sur le serveur. Plus précisément, la vérification permet de définir le style de navigation de la page actuelle :
js var lis = document.querySelectorAll('header nav li'); var i = lis.length; while (i--) { var a = lis[i].querySelector('a'); var section = a.getAttribute("data-section"); if (new RegExp(section).test(document.location.href)) { a.className = 'current'; } }
- Les éléments à largeur fixe ont été remplacés par des
width:100%
ouwidth:auto
fluides.
Cache de l'application
La version mobile de html5rocks utilise le cache d'application pour accélérer le chargement initial et permet aux utilisateurs de lire du contenu hors connexion.
Lorsque vous implémentez AppCache sur votre site, il est très important de ne pas mettre en cache votre fichier manifeste (explicitement dans le fichier manifeste lui-même ou implicitement avec des en-têtes de contrôle de cache lourds). Si votre fichier manifeste est mis en cache par le navigateur, le débogage est un cauchemar. iOS et Android gèrent particulièrement bien la mise en cache de ce fichier, mais ne fournissent pas de moyen pratique de vider le cache comme le font les navigateurs pour ordinateur.
Pour éviter ce problème de mise en cache sur notre site, nous avons d'abord défini App Engine pour qu'il ne mette jamais en cache les fichiers manifestes :
- url: /(.*\.(appcache|manifest))
static_files: \1
mime_type: text/cache-manifest
upload: (.*\.(appcache|manifest))
expiration: "0s"
Deuxièmement, nous avons utilisé l'API JS pour informer l'utilisateur lorsque le téléchargement d'un nouveau fichier manifeste est terminé. Il est invité à actualiser la page:
window.applicationCache.addEventListener('updateready', function(e) {
if (window.applicationCache.status == window.applicationCache.UPDATEREADY) {
window.applicationCache.swapCache();
if (confirm('A new version of this site is available. Load it?')) {
window.location.reload();
}
}
}, false);
Pour économiser le trafic réseau, optez pour un fichier manifeste simple. Autrement dit, n'indiquez pas toutes les pages de votre site. Il suffit de lister les images, les fichiers CSS et les fichiers JavaScript importants. La dernière chose que vous voulez faire est de forcer le navigateur mobile à télécharger un grand nombre d'éléments à chaque mise à jour de l'appcache. N'oubliez pas que le navigateur met en cache implicitement une page HTML lorsque l'utilisateur y accède (et qu'elle inclut un attribut <html manifest="...">
).