TD6 – Responsive Design

Introduction

Les smartphones, les tablettes et tous les appareils de la mobilité demandent de repenser le web d’aujourd’hui. Concevoir un site ou une application Web s’adressant à tous ces médias n’est pas une tâche triviale. Voici un aperçu des nombreuses solutions existantes :

Plus pour nous positionner dans cette jungle que par purisme, nous prendrons deux hypothèses de départ :

Nous adopterons dans ce TD une approche itérative, en rajoutant au fur et à mesure des contraintes pour arriver à ce qui se fait aujourd’hui dans le responsive design.

CSS2

Certaines propriétés n’ont pas attendu ni les nouveaux médias ni le CSS3 pour s’imposer aux développeurs. Elles prenaient déjà tout leur sens sur des sites particulièrement fournis et/ou sur des petits écrans 15 pouces.

Les pourcentages ‘%’

On peut commencer par exprimer toutes les tailles en relatif. C’est ce que nous avons déjà fait en utilisant des dimensions en %. Rappelez vous que la largeur d’un élément en display:block ou en display:flex se calcule par rapport à son containing block, c’est-à-dire son plus proche ancêtre block ou flex. Par défaut, les éléments en block ou flex prennent toute la largeur de leur containing block. Et si on fixe une largeur en pourcentage, ce sera relativement à la largeur du containing block.

  1. Donnez à <body> la width de 100%. Donnez à la propriété margin la valeur auto si ce n’est pas le cas.
  2. Enlevez au besoin la marge de gauche de 10% sur le <aside> et changez les dimensions relatives de <article> et <aside> à respectivement 67% et 33%.

Note : Si adapter les largeurs en pourcentage marche bien, ce n’est pas le cas des hauteurs. Cela est dû au fait que la largeur de la page est connue (c’est la largeur de la fenêtre d’affichage du navigateur) mais sa hauteur ne l’est pas encore… (puisque la page n’est pas encore affichée et que la hauteur va dépendre de la quantité de contenu). Autrement dit, la hauteur de la zone du navigateur où s’affiche la page (viewport height) n’est pas forcément la hauteur de la page 1 (et c’est lié à la présence d’un ascenseur à droite pour descendre dans la page).

max-width et min-width

Les règles précédentes permettent d’avoir un rapport homogène, mais pas un rendu optimal :

Pour contraindre les dimensions maximales et minimales, nous utiliserons max-width, max-height, min-width et min-height, qui prennent le même type de valeur que width et height.

  1. Ajoutez une limite maximum de largeur à <article> et à <aside> de 500px et de 250px.
  2. Ajoutez une limite minimum de largeur à <article> et à <aside> de 200px et 150px.

Overconstraint

Mais que se passe-t-il quand on mélange min-width et des tailles en poucentage ? Prenons l’exemple suivant

<div style="display:flex">
	<div style="width:50%;max-width:400px;">
		Div1
	</div>
	<div style="width:50%;">
		Div2
	</div>
</div>

qui s’affiche comme suit

Div1

Div2


Remarquez en changeant la largeur de votre fenêtre (ou en zoomant) que :

  1. les deux <div> prennent toute la largeur quand <body> a une largeur inférieure à 800px (donc le premier <div> a une largeur de moins de 400px)
  2. mais quand la largeur de <body> est supérieure à 800px, alors les deux <div> ne remplissent plus toute la largeur de <body>. Div2 garde une largeur de 50% mais Div1 ne peut plus prendre les 50% restant car il est contraint par sa largeur maximale de 400px.

Nous allons utiliser display:flex pour mieux mélanger les tailles relatives et les contraintes min-width/max-width. Nous avions déjà vu les règles de la colonne de gauche de cette super page sur FlexBox ; c’était celles qui s’appliquaient au parent. Nous allons maintenant nous pencher sur la colonne de droite qui s’applique aux balises enfants. Regardez particulièrement les propriétés flex-shrink (valeur par défaut 1), flex-grow (valeur par défaut 0). Pour l’instant, nous ne toucherons pas à flex-basis (qui gardera donc son comportement par défaut auto).

  1. Lisez la section sur flex-shrink et flex-grow dans le guide de FlexBox ou tout autre page Web. N’hésitez pas à parler de votre compréhension avec votre professeur.

  2. Donnons un exemple d’utilisation de flex-grow. Votre boulot est de vérifier que vous comprenez son fonctionnement.

    Nous pouvons désormais résoudre le problème précédent avec flex-grow:1;.

    <div style="display:flex">
    	<div style="width:50%;max-width:400px;">
    		Div1
    	</div>
    	<div style="width:50%;flex-grow:1;">
    		Div2
    	</div>
    </div>
    

    qui s’affiche comme suit

    Div1

    Div2

    Maintenant que la largeur de <body> est supérieure à 800px, alors le second <div> voit sa largeur augmenter grâce à flex-grow:1;. Donc les deux <div> remplissent toujours la largeur de <body>.

  3. Changez les largeurs de <article> et <aside> pour qu’elles soient par défaut de 300px et 200px. Mettez les propriétés flex-shrink et flex-grow pour ces deux éléments à 0.
    Bougez la largeur de la page. Est-ce que les largeurs de <article> et <aside> changent ?

  4. Nous souhaitons que quand l’écran est trop large, l’espace restant soit réparti entre <article> et <aside> de telle sorte que l’espace gagné par <article> soit 3 fois plus grand que celui gagné par <aside>.
    Quelle propriété CSS devez-vous utiliser pour avoir ce comportement ? Implémentez ce comportement.

  5. Pour vérifier que vous avez bien répondu à la question précédente, redimensionnez la fenêtre du navigateur pour que la largeur de <body> soit de 620px.
    Quelles devraient être selon vous les largeurs de <article> et <aside> ? Inspectez maintenant les largeurs de <article> et <aside> pour vérifier votre calcul.

  6. Nous souhaitons que quand l’écran est trop petit, <article> diminue de deux tiers de la largeur à supprimer et <aside> diminue du reste.
    Quelle propriété CSS devez-vous utiliser pour avoir ce comportement ? Implémentez ce comportement.

Problèmes plus complexes

Il arrive un moment où diminuer encore la taille n’a plus de sens. Il faut prendre des mesures draconiennes, par exemple passer <aside> sous <article> ou carrément supprimer <aside>.

Les règles CSS déjà vues en TDs ne permettent pas de coder ce genre de comportement. Il nous faut une façon d’écrire du CSS qui ne sera valide que dans des cas précis. Nous verrons dans la prochaine section comment cela est possible en CSS3.

Votre site de Chuck Norris sur mobile

Les outils pour travailler ?

Jusqu’ici on pouvait considérer que tous les outils de développement d’Internet Explorer / Firefox / Chrome étaient égaux. En fait celui de Chrome était déjà un peu meilleur :

En tout cas, pour le reponsive design il n’y a pas photo : Chrome (ou son pendant libre Chromium) est vraiment votre “best-friend-ever”.

Que fait mon navigateur Web sur téléphone par défaut pour un site ?

Comment peut-on rendre un site internet compatible mobile à moindre coût ?

Voici l’algorithme (simplifié) opérant par défaut :

Et ça marche ! De fait, c’est ce que font par défaut les smartphones quand ils tombent sur un site non responsive.

  1. Dans les outils développeurs (F12) de Chrome/Chromium, passez dans le device mode Outil pour mobile “Samsumg Galaxy S5” sous Chrome/Chromium et rechargez votre page. Constatez que le site s’affiche en tout petit.
  1. Vérifiez que la taille du <body> est de 980px, ce qui signifie que l’algorithme précédent a été utilisé pour l’affichage.
    Remarquez aussi que la largeur de l’affichage est de 360px, ce qui signifie d’un zoom arrière est effectué.

Même si cela marche, on ne peut pas dire que cela soit optimal. L’utilisateur mobile n’a pas la même attente que l’utilisateur sur ordinateur, il veut avoir accès rapidement aux informations essentielles, sans fioritures. On imagine que sur une smart watch par exemple un site comme méteo france serait largement plus dépouillé (sur une smartwatch elle afficherait un nuage ou un soleil et la température par exemple).

Typiquement nous voulons enlever des parties entières du site suivant la taille de l’écran.

La première chose à faire est donc de demander aux navigateurs de ne plus faire l’algorithme précédent (puisqu’on va le gérer nous-mêmes) dans la balise <head> :

 <meta name="viewport" content="width=device-width, initial-scale=1">

Ajouter cette instruction au site de Chuck Norris et visualisez avec Chrome en choisissant un smartphone. Inspectez la largeur de <body>. Que constatez-vous ?

Vous devez constatez que l’algorithme précédent ne s’applique plus. En gros le navigateur n’essaie plus d’être intelligent : il vous laisse prendre le relai.

La solution technique CSS3 : les media queries

Les media queries sont un jeu d’options ajoutées à la norme CSS3 et qui permettent de définir des règles CSS qui ne s’appliqueront que sous certaines conditions spécifiques.

Il existe deux manières différentes de faire appel à une media query :

Une media query fonctionne de la manière suivante : la condition est évaluée et retourne une valeur “vrai” ou “faux”. Si la valeur est vraie, le fichier CSS/ la règle CSS (selon la méthode employée) est appliquée.

Chaque condition est formée à partir d’une ou plusieurs conditions de base. Parmi l’ensemble des conditions possibles, nous allons nous intéresser particulièrement aux suivantes :

Les conditions de base peuvent être combinées ensemble pour former des conditions complexes en utilisant les opérateurs logiques :

Exemple : la règle (min-width: 500px) and (min-height: 800px) n’est vraie que si la largeur de l’affichage est supérieure (ou égale) à 500px et la hauteur supérieure à 800px.

  • Allez sur le site Bootstrap. Faites varier la largeur du navigateur et constatez que la mise en page change (menu variable, texte qui prend toute la largeur ou non, icône qui disparait, …).
  • Utilisez le device mode pour afficher les media queries (cliquer sur les 3 points verticaux du device mode pour afficher ces media queries).
  • Que se passe-t-il visuellement dans le menu lorsque vous redimensionnnez la fenêtre autour du point de rupture situé à 768px ?

Les points de ruptures.

Afin d’organiser nos media queries, on utilise en général 3 à 4 valeurs de largeur d’écrans, par exemple :

  1. en dessous de 768px ne plus afficher la table de comparaison (de toute façon s’il ne doit rester qu’un seul, ce sera Chuck Norris).
  2. en dessous de 480px faire en sorte qu’<aside> et <article> soient en colonne et non plus en ligne.
  3. (Optionnel) Sur une smartwatch (width 168px), n’affichez que les citations de Chuck Norris contenues dans le <aside>.

Mettez-moi un burger au menu !

Quand la taille de l’écran est limitée, une bonne pratique en responsive design est de changer l’affichage du menu pour un bouton burger :

Burger button, three horizontal lines, (two corresponding to the bread, and the one for the meal)

Lorsque l’on cliquera dessus, le menu apparaîtra. Cela permet de ne pas perdre de place sur la page lorsque le menu est fermé. Pour fixer les idées, nous voulons un menu qui apparaît latéralement à la manière des exemples suivants :

Dans l’exercice suivant, nous allons coder un menu burger HTML/CSS (donc sans JavaScript) qui apparait quand la souris passe au dessus du burger (la gestion du clic nécessiterait du JavaScript). (Notez au passage que codepen.io est un très bon outil pour découvrir de nouvelles techniques !)

Nous allons coder un deuxième menu, identique au premier dans son contenu, mais avec une mise en page différente. Nous allons afficher l’un ou l’autre des menus en fonction de la taille de l’écran.

  1. Ajouter un <div> de classe burger contenant l’image de burger (largeur 50px) juste avant le menu <nav>.
  2. À partir du point de rupture ‘Smartphone’, faites disparaître l’ancien menu et faites apparaître le <div class="burger"> à droite de la page (à la place du menu).
  3. Implémentez le deuxième menu avec les caractéristiques suivantes :

    • Son contenu est

      <div class="burger">
        <img src="images/burger.png" alt="burger" width="50">
        <div id="menu2">
          <div><a href="./index.html">Accueil</a></div>
          <div><a href="./facts.html">Facts</a></div>
          <div><a href="./news.html">Actualités</a></div>
          <div><a href="./contact.html">Contact</a></div>
       </div>
      </div>
      
    • il se positionne par rapport à la fenêtre d’affichage (quelle valeur de position faut-il mettre ?), tout en haut à gauche.
    • il est visuellement au-dessus des autres éléments du site (cherchez sur le Web la propriété z-index)
    • les sous-menus sont disposés verticalement.
  4. Cachez par défaut en CSS le menu2. Au survol du <div class="burger">, faites-le réapparaître.

Voilà ce qu’on devrait pouvoir obtenir:

menu_burger.gif

Note : Le hover sur les sous-menus n’a pas de sens sur téléphone portable (mais certains explorateurs contournent cela, par exemple en déclenchant le hover avec un “clique” sur l’élément à hover). Il faudra gérer le clic avec du JS. La bonne solution est … suspense, vous la verrez en 2ème année.

La mobilité en général

Les contraintes liées à la mobilité ne se limitent pas au responsive design. Pour vous donner une idée plus complète, voici d’autres exemples de contraintes fortes qui viennent s’ajouter :

  1. L’unité vh permet maintenant de définir une taille de 0 à 100 relative au viewport.