Adapter votre site HTML5 pour les mobiles

Eric Bidelman

Introduction

Le développement pour le Web mobile est au cœur des sujets d'actualité. Cette année, pour la première fois, les smartphones ont éliminé les PC. De plus en plus d'utilisateurs utilisent un appareil mobile pour parcourir le Web. Il est donc devenu essentiel pour les développeurs d'optimiser leurs sites pour les navigateurs mobiles.

Pour un grand nombre de développeurs, le champ de bataille du mobile est encore inexploré. Nombreux sont les propriétaires de sites qui négligent l'utilisation d'appareils mobiles. Au lieu de cela, le site a été conçu principalement pour la navigation sur ordinateur et se dégrade mal dans les navigateurs mobiles. Ce site (html5rocks.com) ne fait pas exception. Au lancement, nous nous efforçons de créer une version mobile du site.

Créer un site html5rocks.com adapté aux mobiles

À titre d'exercice, j'ai pensé qu'il serait intéressant d'utiliser html5rocks (un site HTML5 existant) et de l'enrichir par une version adaptée aux mobiles. Je m'inquiétais surtout du minimum de travail nécessaire pour cibler les smartphones. Le but de mon exercice n'était pas de créer un site mobile entièrement nouveau et de gérer deux codebases. Cela aurait pris une éternité et aurait été une énorme perte de temps. Nous avions déjà défini la structure du site (balisage). Nous avions une apparence et un style (CSS). La fonctionnalité de base (JS) était là. Il y a de nombreux sites dans le même bateau.

Cet article examine comment nous avons créé une version mobile de HTML5rocks optimisée pour les appareils Android et iOS. Il 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 un site m.html5rocks.com ou toute autre forme d'imbrication de ce type. Vous pouvez utiliser le langage HTML5rock tel quel, avec en plus l'avantage d'un élément à l'aspect élégant et adapté à un appareil mobile.

html5rocks.com pour ordinateur Mobile html5rocks.com
html5rocks.com sur ordinateur (à gauche) et mobile (à droite)

Requêtes de médias CSS

Les feuilles de style dépendantes du média sont compatibles depuis un certain temps avec HTML4 et CSS2. Exemple :

<link rel="stylesheet" media="print" href="printer.css">

ciblerait les appareils d'impression et fournirait un style spécifique pour le contenu de la page imprimée. CSS3 va encore plus loin dans l'idée des types de support et améliore leur fonctionnalité avec les requêtes média. Les requêtes média améliorent l'utilité des types de médias en permettant un libellé plus précis des feuilles de style. Cela permet de personnaliser la présentation du contenu pour une gamme spécifique de périphériques de sortie sans avoir à modifier le contenu lui-même. Cela semble idéal pour une mise en page existante qui doit être modifiée !

Vous pouvez utiliser des requêtes média dans l'attribut media de vos feuilles de style externes pour cibler la largeur d'écran, la largeur de l'appareil, l'orientation, etc. Pour obtenir la liste complète, consultez les spécifications des requêtes média du W3C.

Ciblage de tailles d'écran

Dans l'exemple suivant, phone.css s'appliquerait aux appareils que le navigateur considère comme "portables" ou aux appareils dont la largeur d'écran 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 média, les navigateurs non compatibles avec CSS3 ignorent la règle.

Le code suivant ciblerait des 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 des tags <style> intégrés. Les éléments suivants ciblent les types de supports all en mode portrait:

 <style>
  @media only all and (orientation: portrait) { ... }
 </style>

media="handheld"

Nous devons faire une pause pour discuter de media="handheld". Le fait est qu'Android et iOS ignorent media="handheld". L'affirmation est que les utilisateurs passeront à côté du contenu haut de gamme fourni par les feuilles de style ciblant media="screen", et que les développeurs seront moins susceptibles de conserver une version de media="handheld" de qualité inférieure. Ainsi, dans le cadre de leur devise "Web intégral", la plupart des navigateurs modernes pour smartphones ignorent simplement les feuilles de style pour appareils portables.

Il serait idéal d'utiliser cette fonctionnalité pour cibler les appareils mobiles, mais plusieurs navigateurs l'ont implémentée de différentes manières:

  • Certains ne lisent que la feuille de style portable.
  • Certains ne peuvent lire que la feuille de style pour ordinateur portable, le cas échéant. Dans le cas contraire, la feuille de style de l'écran est utilisée par défaut.
  • Certains lisent à la fois la feuille de style pour ordinateur portable et la feuille de style d'é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", l'astuce consiste à mettre en majuscules la valeur de l'attribut multimédia dans 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 média

Les requêtes média sont très utilisées sur les mobiles html5rocks. Ils nous ont permis d'ajuster la mise en page sans avoir à apporter de modifications importantes à notre balisage de modèle Django, ce qui nous sauve autant ! De plus, leur compatibilité avec les différents navigateurs est plutôt bonne.

Dans la section <head> de chaque page, vous verrez 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 des largeurs d'écran inférieures à 800 pixels. Sa requête média concerne les smartphones (~320 pixels) et l'iPad (~768 pixels). Résultat: nous remplaçons progressivement les styles dans base.css (uniquement si nécessaire) pour améliorer l'apparence sur mobile.

Voici quelques-unes des modifications de style appliquées par mobile.css:

  • Réduit les espaces blancs/les marges intérieures supplémentaires sur le site. Les petits écrans signifient que l'espace est précieux !
  • Supprime :hover états. Elles ne sont jamais vues sur les appareils tactiles.
  • Permet de définir la mise en page sur une seule colonne. Nous reviendrons sur ce point.
  • Supprime les box-shadow autour de l'élément div principal du conteneur du site. Les ombres de grande taille réduisent les performances de la page.
  • Utilisation du modèle de zone flexible CSS box-ordinal-group pour modifier l'ordre de chaque section sur la page d'accueil. La mention "APPRENDRE LES GROUPES DE FONCTIONNALITÉS HTML5 PRINCIPAUX" s'affiche 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. CSS flexbox FTW!
  • Supprime opacity modifications. La modification des valeurs alpha est un atout majeur sur les mobiles.

Balises Meta pour mobile

Mobile WebKit est compatible avec quelques goodies qui offrent une meilleure expérience de navigation aux utilisateurs sur certains appareils.

Paramètres de la fenêtre d'affichage

Le premier métaparamètre (et celui que vous utiliserez le plus souvent) est la propriété de la fenêtre d'affichage. Définir une fenêtre d'affichage indique au navigateur comment le contenu doit s'afficher sur l'écran de l'appareil et indique au 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 de zoomer, 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 de la fenêtre d'affichage en permettant aux développeurs d'indiquer 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 propriété Meta target-densitydpi sur device-dpi. Cela empêche Android d'effectuer un scaling sur votre page Web et vous permet d'effectuer 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.

Navigation en plein écran

Deux autres méta-valeurs sont au format iOS-sfic. apple-mobile-web-app-capable et apple-mobile-web-app-status-bar-style afficheront le contenu de la page en mode plein écran comme une application et rendra la barre d'état translucide:

 <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étaoptions disponibles, consultez la documentation de référence de Safari.

Icônes de l'écran d'accueil

Les appareils iOS et Android acceptent également les liens rel="apple-touch-icon" (iOS) et rel="apple-touch-icon-precomposed" (Android). Ceux-ci créent une icône tape-à-l'œil 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 Meta pour mobile

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 la page verticalement qu'horizontalement. Pour les mobiles, la mise en page verticale à une seule colonne est préférable. Pour html5rocks, nous avons utilisé les requêtes média CSS3 afin de créer cette mise en page. Là encore, sans modifier le balisage.

Index des tutoriels. Tutoriel. sur la page &quot;Fonctionnalités HTML5&quot;. Page des profils de l&#39;auteur.
Mise en page verticale à colonne unique dans l'ensemble du site.

Optimisations pour les mobiles

La plupart des optimisations que nous avons apportées sont des éléments qui auraient dû être réalisés dès le départ. Par exemple, vous pouvez réduire le nombre de requêtes réseau, la compression JS/CSS, la compression gzip (disponible sans frais sur App Engine) et les manipulations DOM. Il s'agit des bonnes pratiques courantes, mais il arrive qu'elles soient négligées lorsqu'un utilisateur se précipite sur un site.

Masquer automatiquement la barre d'adresse

Les navigateurs mobiles n'ont pas l'espace d'écran de leur homologue pour ordinateur. Et, sur différentes plates-formes, vous pouvez parfois vous retrouver avec une ancienne barre d'adresse en haut de l'écran, même après le chargement de la page.

Pour résoudre ce problème, il vous suffit de faire défiler la page à l'aide de JavaScript. Même le fait d’effectuer cette opération d’un pixel corrigera l’embête de la barre d’adresse. 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:

Barre d&#39;adresse.
Une barre d'adresse insatisfaite occupe tout l'espace sur l'écran.
  // 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 le bureau.

Réduire les requêtes réseau et économiser la bande passante

Il est bien connu que la réduction du nombre de requêtes HTTP peut considérablement améliorer les performances. Les appareils mobiles limitent davantage le nombre de connexions simultanées que le navigateur peut établir. La réduction de ces requêtes superflues est donc encore plus bénéfique pour les sites mobiles. De plus, il est essentiel de supprimer chaque octet, car la bande passante est souvent limitée sur les téléphones. Vous facturez peut-être 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 html5rocks:

  • Supprimez les iFrames. Ils sont lents ! Une grande partie de notre latence provenait de widgets de partage tiers (Buzz, Google Friend Connect, Twitter, Facebook) sur les pages de tutoriels. Ces API ont été incluses via des balises <script> et créent des cadres iFrame qui réduisent la vitesse de la page. Les widgets ont été supprimés de la version mobile.

  • display:none : dans certains cas, nous masquions le balisage s'il ne correspondait pas au profil mobile. Les quatre encadrés arrondis situés en haut de la page d'accueil en sont un bon exemple:

Boutons en forme de cases sur la page d&#39;accueil.
Boîtes sur la page d'accueil

Elles n'apparaissent pas sur le site mobile. Il est important de noter que le navigateur envoie toujours une requête pour chaque icône, bien que son conteneur soit masqué avec display:none. Il ne suffit donc pas de masquer ces boutons. Non seulement cela serait un gaspillage de bande passante, mais l'utilisateur ne verrait même pas les fruits de ce gaspillage de bande passante ! La solution consistait à créer une valeur booléenne "is_mobile" dans notre modèle Django afin d'omettre de manière conditionnelle des sections de HTML. Lorsque l'utilisateur consulte le site sur un appareil connecté, les boutons sont omis.

  • Cache d'application : cela nous permet non seulement d'utiliser le mode hors connexion, mais également d'accélérer le démarrage.

  • Compression CSS/JS : nous utilisons le compresseur YUI au lieu du compilateur Closure, principalement parce qu'il gère à la fois CSS et JS. Nous avons rencontré un problème : les requêtes média intégrées (requêtes multimédias qui apparaissent dans une feuille de style) sont intégrées dans le compresseur YUI 2.4.2 (voir ce problème). L'utilisation de YUI Compressor 2.4.4+ a résolu le problème.

  • Utilisation de sprites CSS lorsque cela est possible

  • Utilisation de pngcrush pour la compression d'image.

  • Utilisation de dataURI pour les petites images. L'encodage Base64 ajoute une taille d'environ 30%ou plus à l'image, mais enregistre la requête réseau.

  • Chargement automatique de la recherche personnalisée Google à l'aide d'un seul tag de script au lieu de la charger dynamiquement avec google.load(). Ce dernier effectue une requête supplémentaire.

<script src="//www.google.com/jsapi?autoload={"modules":[{"name":"search","version":"1"}]}"> </script>
  • Notre code imprimante et Modernizr étaient inclus sur chaque page, même s'ils n'étaient jamais utilisés. Modernizr est un excellent outil, mais il exécute un tas de tests à chaque charge. Certains de ces tests apportent des modifications coûteuses au DOM et ralentissent le chargement des pages. Maintenant, nous incluons ces bibliothèques uniquement sur les pages où elles sont réellement nécessaires. - 2 demandes :)

Autres ajustements des performances:

  • Déplacement de tout le code JS en bas de la page (si possible).
  • Suppression des tags <style> intégrés.
  • Recherches DOM mises en cache et manipulations DOM réduites : chaque fois que vous appuyez sur le DOM, le navigateur effectue un reflow. Les rediffusions sont encore plus coûteuses sur un appareil mobile.
  • Déchargement du code côté client inutile sur le serveur. Plus précisément, la vérification permettant 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 de largeur fixe ont été remplacés par un width:100% ou un width:auto fluide.

Cache de l'application

La version mobile de html5rocks utilise le cache d'application pour accélérer le chargement initial et permettre aux utilisateurs de lire le 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 (que ce soit explicitement dans le fichier manifeste lui-même ou implicitement avec des en-têtes de contrôle de cache volumineux). Si votre fichier manifeste est mis en cache par le navigateur, c'est un cauchemar à déboguer. iOS et Android mettent particulièrement bien en cache ce fichier, mais ne proposent pas de moyen pratique de vider le cache comme le font les navigateurs pour ordinateur.

Pour empêcher la mise en cache de notre site, nous commençons par configurer App Engine de sorte 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"

Ensuite, nous avons utilisé l'API JavaScript pour informer l'utilisateur de la fin du téléchargement d'un nouveau fichier manifeste. 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, privilégiez la simplicité de votre fichier manifeste. c'est-à-dire de ne pas mentionner toutes les pages de votre site. Il vous suffit de lister les fichiers image, CSS et JavaScript importants. La dernière chose à faire est de forcer le navigateur mobile à télécharger un grand nombre d'éléments à chaque mise à jour du cache d'application. N'oubliez pas que le navigateur met implicitement en cache une page HTML lors de la visite de l'utilisateur (et qu'il inclut un attribut <html manifest="...">).