CSS pour mobiles

Cet article décrit la démarche que j'ai prise pour afficher mes pages Web sur un périphérique mobile. J'y décris les difficultés générées par la petitesse de l'écran.

Je viens tout juste de m'acheter un téléphone "intelligent". Rien d'extraordinaire, un Samsung Galaxy CORE LTE. Je me suis familiarisé autant avec la saisie des données qu'avec sa configuration. Ça bien été et c'est alors que je me suis demandé à quoi ressemblaient mes trois sites sur un "mobile".

Premières impressions

J'ai été surpris par le rendu. Le contenu était facile à lire même si les pages devenaient très très longues. Le hic! la navigation. Lors de l'ouverture du menu, tous les items de la liste étaient microscopiques: il n'était pas impossible de lire le détail mais impossible de les taper avec un doigt.

Une solution possible!

S'il n'y avait que la grosseur des doigts comme problème, la solution proposée par Al Jaffee dans son livre intitulé "Al Jaffee's MAD Inventions" publié en 1978 pourrait s'appliquer. Cependant, il y a aussi le problème de rendre le contenu lisible car le patrimoine écran sur lequel on doit afficher le contenu est réellement restreint. Comme il est décrit dans Quicktools.com à sa section "screenfly", ces écrans vont de 176x270 pour un Motorola RACQ V3M à 414x736 pour un Apple iPhone 6+ en passant par 320x640 pour un Samsung Galaxy S4. Je note aussi que les mobiles s'utilisent surtout en mode "portrait".

C'est à ce moment que je me suis intéressé à Android et aux problèmes associés avec l'affichage sur un petit écran "tactile". La multiplication des appareils, des formats et des résolutions impose aux concepteurs Web de s'adapter à l'utilisateur. Les notions d'interface utilisateur et d'expérience utilisateur sont au centre du design pour mobile.

Voyons maintenant quelques notions de base. En premier lieu, voyons ce qu'on entend par "viewport".

Viewport

Le viewport désigne schématiquement la surface de la fenêtre d'un navigateur. Cependant, sur un appareil mobile, cette notion prend un sens différent. Sur un mobile, le navigateur ne dispose pas d'une fenêtre réelle ni de barres de défilement ni de boutons pour redimensionner l'affichage. C'est que tout y est prévu pour naviguer de manière "tactile". Sur un mobile, on fait glisser pour faire défiler les pages, on "zoome" soit en écatant ou en pinçant les doigts et on lance ce sur quoi on tape. Tous des mouvements qui ne sont pas disponibles sur un écran d'ordinateur portable ou de bureau.

Sur un mobile, il faut distinguer la surface réelle en pixels réels et la surface vituelle en "pixels CSS". La première est celle des pixels qui composent la matrice de l'écran, c'est celle que le constructeur décrit. La dernière est celle donnée par device-width/device-height ou encore par screen.width/screen.height: il s'agit du nombre de pixels virtuels que le terminal pense avoir et sur lequel il fonde son affichage. Hélas! ces deux surfaces ne correspondent pas toujours.

En plus, notons que par défaut la taille du viewport d'un terminal mobile ne correspond ni à la taille réelle de son écran ni à celle en "pixels CSS". Elle est généralement bien supérieure à la surface physique, afin de pouvoir y caler n'importe quelle page web en lui affectant un niveau de (dé)zoom pour la cadrer dans l'écran.

Finalement, si tout ce qui précède n'est pas clair, la valeur initiale du viewport ne dépend pas non plus du terminal mais du navigateur mobile (et peut parfois même être modifiable par l'utilisateur dans ses réglages).

Ce sujet est traité de façon beaucoup plus approfondie dans "Comprendre le Viewport dans le Web mobile", un article très intéressant écrit par Raphael (Intégrateur du Dimanche, Strasbourg) sur le site alsacréation.

La balise meta viewport

Heureusement HTML offre une solution qui permet de ne pas avoir à comprendre le paragraphe précédent. Il s'agît de la balise meta viewport. Elle donne au navigateur des instructions sur la façon de contrôler les dimensions et la mise à l'échelle de la page, et doit figurer dans l'en-tête du document.

En voici un exemple:

<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0">

On y dit que la largeur d'affichage sera celle de l'écran, que le zoom initial sera 1, que l'utilisateur ne peut "zoomer" l'affichage. C'est ce que j'utilise sur ce site.

Comment lier les fichiers CSS

Passons maintenant à la façon de lier les fichiers CSS pour l'affichage de bureau et l'affichage mobile. Avant de penser mobile, j'utilisais

<link rel="stylesheet" href="/include/layout.php" type="text/css" media="screen" />
<link rel="stylesheet" type="text/css" href="/include/print.css" media="print" />

c'est à dire, layout.php pour l'affichage sur un écran et print.css pour l'impression

L'usage de layout.php requiert une explication
L'usage de layout.php au lieu de layout.css dans ce site s'explique par le fait que layout.php est un script PHP qui produit un fichier CSS permettant ainsi des conditions initiales de couleurs, de grandeurs de caractères, de bordures ou de rayons de bordures. C'est une façon d'introduire des variables en CSS.

Dans le cas où on utilise un affichage séparé pour le mobile, on doit modifier ces liens comme suit:

<link rel="stylesheet" href="/include/layout.php" type="text/css" media="only screen and (min-width: 641px)">
<link rel="stylesheet" href="/include/mobile.css" type="text/css" media="only screen and (max-width: 640px)">
<link rel="stylesheet" type="text/css" href="/include/print.css" media="print" />

Structure des pages

Quoique générée par du code PHP, la première version de ce site utilisait des tables HTML emboitées l'une dans l'autre pour rendre le contenu. De plus, le site était statique car je n'utilisais pas de code Javascript sauf pour le menu. Lorsque j'ai appris que cette façon de faire était plutôt désuette, j'ai modifié sa structure en utilisant des tables CSS à la place des tables HTML et en définissant les largeurs (width) des conteneurs en pourcentage, ce qu'on appelle un satyle "liquide".

Cette modification de la structure m'a causé quelques problèmes relié au fait que, dans certaines circonstances assez extrèmes, CSS perdait le contrôle de la largeur des pages, les affichant sur plusieurs largeurs d'écran. Comme c'était exceptionnel, je n'en ai pas tenu compte.

Cependant, lorsque j'ai voulu afficher mes pages sur un mobile, je n'arrivais jamais à "zoomer" la page à l'intérieur de "viewport" du mobile. C'était partiulièrement visible avec le simulateur de mobile qui vient avec le fureteur Chrome Canary où je voyais mes pages utiliser tous les pixels sans pour autant réduire l'image dans le "viewport"

J'ai alors abandonné cette structure pour utiliser la structure qui suit:

<html>
  <head>
    ...
  </head>
  <body>
    <div id="menu">
      <!-- Affichage du bouton  -->
    </div>
    <nav id="menus">
      <!-- Code PHP pour la construction et l'affichage du menu -->
    </nav>
    <div id="container">
      <header id="banner">
        <!-- Affichage de l'entête de page (titre et date) -->
      </header>
      <article id="template">
        <!-- "PHPLIB Lib Template" génère et affiche le contenu de la page -->
      </article>
    </div>
    <footer>
      <!-- Affichage du pied de page -->
    </footer>
  </body>
</html>

La structure est toujours "liquide" mais n'utilise plus les tables CSS. J'ai aussi commencé à utiliser les nouvelles balises de HTML5 comme <nav> et <article>. Avec cette structure, je n'ai eu aucon problème avec les mobiles.

Rendu de cette page sur un mobile

Affichage sur mobile

Contrairement à ce qui se passe pour l'affichage sur écran d'ordinateur alors que le lecteur peut voir tout le contenu des pages en faisant défiler les écrans, j'ai été inspiré par la façon dont Wikipedia affiche ses pages sur un mobile. On le divise en sections dont seulement le titre, précédé par un symbole indiquant au lecteur qu'il peut taper et faire dérouler le contenu de la section.

J'ai alors décidé de faire pareil. Comme entêtes de section, j'ai fait un choix tout à fait naturel: les balises <h1>. Premier problème: trouver un moyen jQuery pour sélectionner tout le contenu entre les balises et le faire disparaître. Comme on va le voir, la fonction nextUntil() effectue ce travail. Voici le code en quelques étapes:

  1. Il faut en premier lieu vérifier que le code ne va s'appliquer qu'aux mobiles. J'ai considéré qu'une largeur d'écran de moins que 640 pixels indiquait un mobile
    if ($(window).width() <= 640){
      // le code va ici
    }
  2. Après le chargement du DOM, faire en sorte que tout le contenu entre les balises <h1> soit invisible, ne laissant que le titre et le symbole ▼ indiquant qu'on peut faire apparaître le contenu pour le lire
    $('#content h1').each(function(index, value){
      $(this).nextUntil('#content h1').css("display", "none");
      $(this).addClass('h1closed');
    })
  3. C'est un bon départ mais il arrive que tout le contenu qui se trouve après la dernière balise <h1> du document est disparu, même le bas de page, car la fonction nextUntil() agît comme la finction nextAll() lorsqu'elle ne trouve pas sa cible. Pour y remédier, j'ai donc ajouté une balise <h1> artificiellement à la fin du document et je lui ai attribuée l'id de "StopuntilNext" qui, dans le code qui suit, fait réapparaître le bas de page.
    $('#content h1 #StopnextUntil').nextAll().css("display", "block");
    
  4. Il ne reste plus maintenant qu'à réagir lorsque le lecteur tape sur un titre
    $('#content h1').click(function(){
    	 $(this).toggleClass('h1closed').toggleClass('h1open');
    	 if ($(this).nextUntil('#content h1').css('display') == 'none')
    		  $(this).nextUntil('#content h1').css("display", "block");
    	 else
    		  $(this).nextUntil('#content h1').css("display", "none");
    })

Constatations

J'ai vérifié ce code sur tous mes navigateurs. Ça fonctionne très bien sur Internet, Chrome, Opera et Dolphin. Ce n'est pas le cas sur Firefox. Le navigateur Dolphin cause au autre problème.

Firefox pour Android: une exception

Firefox pour Android interprète très bien les commandes CSS et il affiche le site comme on s'y attend. Cependant, il semble ignorer le code jQuery de gtro.js délimité par

if ($(window).width() <= 640){
  // le code va ici
}

dont j'ai parlé plus haut car le code intérieur à cette conditionnelle ne s'exécute pas. Toutes les sections qui devrait être cachées sont affichées.

Navigateur Largeur Hauteur
Internet 360 640
Firefox 980 480
Opera 360 525
Chrome 360 559
Dolphin 540 786

J'ai trouvé pourquoi en faisant quelques tests. Sur chacun des fureteurs de mon mobile, j'ai affiché le largeur et la hauteur des écrans. Voici le résultat de ces tests:

Firefox est le seul navigateur qui ne rend pas les pages comme il le devrait et c'est parce que son interpréteur Javascript inverse les valeurs de la hauteur et de la largeur. J'ai alors substitué le code qui suit à la conditionnelle originale.

var width = $(window).width();
var height = $(window).height();
if (width > height)
	 width = height;

if (width < 640){ // Firefox for Android detects my Galaxy's width as 980px
	// le code à exécuter va ici
}

Avec cette modifications, les pages sont rendues correctement sur tous les navigateurs de mon mobile.

Dolphin

On utilise de plus en plus le caractère unicode "" pour symboliser un menu. Voici comment je l'affiche en HTML

<div id="menu" class="no-print">&#9776;</div>

où "&#9776;" représente le caractère unicode "☰". Le problème avec le navigateur "Dolphin" vient de ce que ce caractère ne s'affiche pas. Comme il est de couleur blanche sur un fond noir de sorte qu'on ne le voit pas dans l'entête de la page et qu'on est incapable d'ouvrir le menu.

Je n'ai pas trouvé de solution à ce problème. Je l'ai contourné en donnant une dimension fixe en pixels à son emplacement et en lui attribuant un fond gris foncé de sorte que l'utilisateur peut ouvrir le menu en tapant sur le gris foncé. Cependant, quoique l'utilisateur peut voir une région de l'entête qui est un peu plus pâle, elle n'est pas indiquée comme était là où il faut taper pour ouvrir le menu. Voici le code CSS qui réalise cela.

#menu {
	 position: absolute;
	 top: 13px;
	 left: 15px;
	 color:#fff;
	 background-color: #222;
	 width: 45px;
	 font-size: 2.5em;
	 text-align:center;
	 overflow:hidden;
	 z-index: 3000;
}

Conclusion

La transition de mes sites vers les mobiles a été assez facile. Cependant, j'ai dû apporter des modifications importantes au rendu des menus.


Pour toute question ou commentaire
E-Mail
page modifiée le 21 août 2015 à 15:48:21. []