CSS : responsive web design avec les media queries de CSS3

Internet mobile

Dans un passé encore récent un site devait s'afficher seulement sur un écran d'ordinateur de bureau voire sur un écran de PC portable. Mais dans les deux cas la largeur de l'écran était supérieure à 900 pixels. Et donc le plus souvent la largeur de chaque page du site était réglée sur 900 pixels.

Mais l'internet mobile c'est à dire la visite de sites à partir de terminaux disposant de petits écrans (tablettes et smartphone) a connu un développement extraordinaire.
Qu'un site ne fonctionne plus (ou très mal) sur ces petits écrans n'est plus acceptable car les outils existent !

Trois solutions possibles

L'adaptabilité d'un site à tous types d'écrans est appelé le "responsive web design".

Dans ce chapitre je n'aborderai que la solution CSS : les media queries au travers d'un exemple.

Un exemple

Imaginons un site dont chaque page comprend quatre grandes divisions :

Le corps de la page (conteneur SECTION) comprend beaucoup de texte répartis dans sixe petites boites (élément DIV affecté de la classe "boite").

Le rendu

Observez le rendu

Affichez la page sur un grand écran (PC de bureau ou PC portable).
Observez que les six boites vertes sont côte à côte.
Progressivement réduisez la largeur de la fenêtre : les boites vertes passent à trois de front (donc sur deux lignes) puis à deux de front (donc sur 3 lignes) ; réduisez encore la fenêtre, les boites vertes sont les unes sous les autres. Bémol : elles sont toujours alignées à gauche même quand il y en 4 sur la première lignes et 2 sur la seconde ; ce qui est un peu disgracieux ...
Par contre les boites bleues occupent toujours toute la largeur de l'écran.

Si vous testez avec une tablette n'hésitez pas à orienter celle-ci en "portrait" puis en "paysage".

Le code de la partie body (extrait)

Il y a en fait six DIV avec la classe "boite".

<body> <header> <h1>Titre général de la page</h1> </header> <nav> <h2>Zone de navigation</h2> </nav> <section> <div class ="boite"> <h2>Titre de l'article</h2> <p>Contenu du texte ... <br>... <br>...</p> </div> <div class ="boite"> <h2>Titre de l'article</h2> <p>Contenu du texte ... <br>... <br>...</p> </div> ... </section> <footer> <h2>Pied de page</h2> </footer>

Aucune difficulté.
Notez que les boites "div class = "boite" sont enfants de SECTION.

Le code de la partie HEAD

... <meta name ="robots" content ="noindex" /> <meta name="viewport" content= "width=device-width, user-scalable=yes" /> <style> /* pour tous les écrans */ header, nav,footer {float : left ; width : 100% ; background : skyblue ; margin-top : 10px;} .boite {float : left ; background : lime; } h1,h2 {text-align : center ; line-height : 40px; font-size : 1.2em; } p {font-size : 1em ; padding : 5px ; } /* écran dont largeur inférieure à 480 */ * {font-size :10px;} section {width : 100%; } .boite{width : 100%; margin-top : 5px; } /* très petit écran */ @media (min-width: 480px) { section{width : 100%; } .boite {width: 100%; } * {font-size : 12px ; } } /* petit écran */ @media (min-width: 800px) { section {width : 760px ; margin : auto; } .boite {width : 47%; margin : 5px 1% 5px 1% ; } * {font-size : 14px ; } } /* écran médium */ @media (min-width: 1000px) { section {width : 900px; margin : auto;} .boite {width : 30%; margin : 5px 1% 5px 1%; } * {font-size : 16px ; } } /* grand écran */ @media (min-width: 1200px) { section {width : 1100px; margin : auto; } .boite {width : 22% ; margin : 5px 1% 5px 1%; } * {font-size : 18px ; } } /* très grand écran */ @media (min-width: 1400px) { section {width : 1300px; margin : auto; } .boite {width : 14% ; margin : 5px 1% 5px 1%; } * {font-size : 20px ; } } </style> ...

La feuille de style interne

Bien évidemment dans le cadre d'un site (avec de nombreuses pages) la feuille de style serait externe.

Une feuille bien structurée

Il y a d'abord toutes les règles indépendantes du type de terminal.
Il y a ensuite les règles relatives aux écrans dont la largeur est inférieure à 480px.
Et enfin des tests par rapport à des "breakpoints" sont effectués sous forme de "media queries".

Largeur des grandes divisions

Les boites header, nav & footer ont toujours pour largeur celle de la fenêtre.
Par contre la largeur de section est fonction de la largeur du terminal.
Il en est de même pour la largeur des DIV affectés de la classe "boite" et de la taille de référence du texte.

Les "media queries" ou requêtes de média

Dans la feuille de style il y a désormais des tests sous forme de requêtes de média ("media queries" en anglais).
Une requête de média commence par "@media" suivi entre parenthèses d'une condition.
Il y a ensuite entre accolades les règles de style qui s'appliquent si la condition est VRAI.

Comment lire les media queries de l'exemple ?

Il y a cinq tests !
A chaque fois on compare la largeur du terminal utilisé par rapport à une valeur en pixels.

Notez bien que les tests doivent être ordonnés par bornes croissantes.

C'est une bonne pratique aujourd’hui de créer son site en version mobile d’abord puis d’utiliser les requêtes de média pour modifier la disposition du code pour les écrans d’ordinateurs ou de tablettes.
Aussi dans la suite des tests il faut comparer d'abord aux petites résolutions jusqu'aux grandes en passant pas les résolutions médiums.

Dans notre exemple :
Si un terminal a une largeur inférieure à 480px (vieux smartphones) aucun test n'est VRAI. Alors SECTION et les éléments "boite" ont par défaut une largeur de 100% de l'écran et taille de base du texte = 10px.
Si le terminal a une largeur au moins égale à 480 mais inférieure à 800, le premier test est VRAI mais pas les autres. Donc la taille de référence du texte est 12px ; SECTION = 100% de large ;largeur de "boite" = 100%, ...
Si le terminal a une largeur au moins égale à 800 mais inférieure à 1000, les deux premiers tests sont VRAI et les autres sont FAUX. Donc ce sont les règles de style contenues dans la deuxième condition qui s'appliquent ; Taille de référence du texte = 14px ; largeur de "boite" =47%.
Si le terminal a une largeur au moins égale à 1000 mais inférieure à 1200, les trois premiers tests sont VRAI et le dernièr est faux. Donc ce sont les règles de style contenues dans la troisième condition qui s'appliquent ; largeur "boite" = 30%, ...
Si le terminal a une largeur au moins égale à 1200 mais inférieure à 1400, les quatre premiers tests sont VRAI. Donc ce sont les règles de style contenues dans la quatrième condition qui s'appliquent ; largeur de "boite" = 22%, ...
Et enfin si le terminal a une largeur au moins égale 1400, les cinq tests sont VRAI c'est donc les règles de la cinquième condition qui s'applique ; largeur de "boite" = 14%, taille de référence = 20px, largeur de SECTION = 1300px avec centrage.

Media queries et flexbox

Vous avez noté que j'ai positionné les six petites boites vertes avec l'outil float.
Or CSS3 propose des technologies de positionnement beaucoup plus sophistiquées. L'outil float doit être réservé au positionnement d'éléments "inline" dans une boite (lettrine, image, etc.).

Reprenons le thème mais en utilisant maintenant l'outil flexbox (boites flexibles ) pour positionner les petites boites vertes.

Le code HTML

Aucun changement ! Et c'est logique le code HTML doit être indépendant du formatage.

La feuille de style

Elle est beaucoup plus simple.

... /* pour tous les écrans */ header, nav,footer {float : left ; width : 100% ; background : skyblue ; margin-top : 10px;} section {display : flex; flex-direction : row ; flex-wrap : wrap; justify-content : space-around; } .boite { background : lime ; width : 200px ; margin-top : 5px; } h1,h2 {text-align : center ; line-height : 40px; font-size : 1.2em; } p {font-size : 1em ; padding : 5px ; } /* écran dont largeur inférieure à 480 */ * {font-size :10px;} section {width : 100%; } /* très petit écran */ @media (min-width: 480px) { section{width : 100%; } * {font-size : 12px; } } /* petit écran */ @media (min-width: 800px) { section {width : 760px ; margin : auto; } * {font-size : 14px ; } } /* écran médium */ @media (min-width: 1000px) { section {width : 900px; margin : auto;} * {font-size : 16px ; } } /* grand écran */ @media (min-width: 1200px) { section {width : 1100px; margin : auto; } * {font-size : 18px ; } } /* très grand écran */ @media (min-width: 1400px) { section {width : 1300px; margin : auto; } * {font-size : 20px ; } } ...

Dans les requêtes de média on ne gère plus la classe "boite".
Par contre dans les règles relatives à tous les écrans :

section {display : flex; flex-direction : row ; flex-wrap : wrap; justify-content : space-around; } .boite { background : lime ; width : 200px ; margin-top : 5px; }

SECTION est le "flex-container" et ses "enfants" sont des "flex-items".
De plus il y a gestion des sauts de ligne et d'une répartition toujours harmonieuses des items au sein de leur conteneur.
Observez le rendu de ce code

Le rendu est plus joli qu'avec "float" ; les boites sont comme "justifiées" dans leur conteneur.
Pour découvrir les nouvelles technologies de positionnement.
CSS3 : une révolution dans le positionnement

La balise META dans la partie HEAD

Vous avez sans doute remarqué que désormais il y a dans la partie HEAD de chaque page une instruction HTML très étrange :

<meta name="viewport" content = "width=device-width, user-scalable=yes" />

A quoi sert cette instruction ?
Cette instruction est fondamentale dans le cadre du Web mobile !

Rôle de cette instruction

Les écrans des mobiles sont beaucoup plus étroits que les écrans de PC (seulement quelques centaines de pixels de large). Pour s'adapter, les navigateurs mobiles affichent le site en "dézoomant" ce qui permet d'avoir un aperçu de l'ensemble de la page mais alors c'est tellement écrit petit que c'est illisible !

Cette zone d'affichage simulée est appelée le viewport.

Attention la valeur du viewport ne dépend pas du terminal mais du navigateur mobile installé sur ce terminal.
Ainsi le viewport est compris entre 800 pixels (Android 3) et 980 (Android 4 et Safari).

Prenons un exemple concret. Votre iphone 6 a une largeur utile d'écran de 377 par 667 pixels ; le viewport possible est de 980 pixels grâce au navigateur safari mobile qui est installé.
Mais grâce à l'instruction meta name ="viewport" content= "width=device-width, user-scalable=yes" la largeur effective ne sera plus que 377 pixels ou (667 selon l'orientation).

Masquer certains éléments

Pour certaines résolutions on peut imaginer que certains éléments ou boites affectées d'une certaine classe soient masqués.
Exemple :

@media (max-width : 600px ) 
{ 
	aside {display : none;}
	.grandecran {display : none; }
}

Sens de cette condition CSS : si la largeur du terminal est inférieure à 601 (écran de smartphone) les éléments ASIDE et les boites affectées de la classe "grandecran" sont masqués !

Responsive design et les images

Pour que les images ne soient jamais rognées sur un petit écran tel celui d'un smartphone il ne faut pas exprimer leur largeur en pixels mais en pourcentage (de la largeur du parent).

Exemple

... <meta name="viewport" content= "width=device-width, user-scalable=yes" /> <style> section {width : 100%; background : skyblue ; margin : auto ; } @media (min-width : 1000px) {section {width : 800px ; }} img.grand {display : block ; width : 80% ; margin : 10px auto 10px auto; } img.petit {display : inline-block ;width : 40%; margin :1% ; } </style></head> <body> <section> <p>Une grande image centrée dans son container : <img src ="../img_bio/ammonite.jpg" class ="grand" /> <p>Deux petites images de front : <br><img src ="../img_bio/acalephe.jpg" class ="petit" /> <img src ="../img_bio/acetabulaire.jpg" class ="petit" /> </section> ..

Ainsi la largeur de chaque image va s'adapter à celle du conteneur parent (SECTION) qui lui même a une largeur fonction de l'écran (800 pixels si grand écran ( > à 1000px) ou 100% de la largeur d'un petit écran ( < à 1000px). Testez ce code

Si vous utilisez un PC pensez à réduire la largeur de la fenêtre

La balise PICTURE de HTML5

Afficher sur l'écran minuscule d'un smartphone une image de haute résolution (donc lourde) n'a pas de sens.
D'autant plus que le débit d'internet mobile est toujours plus faible que celui dont bénéficie un PC (en Ethernet ou WIFI).

Observez attentivement le code HTML ci-dessous !

... <figure> <figcaption>Le col des Aravis en hiver : </figcaption> <picture> <source srcset="../images/aravis_grand.jpg" media="(min-width: 800px)"> <img src="../images/aravis_petit.jpg" /> </picture> </figure> ...

Notez que la balise PICTURE contient un test : si la largeur de la fenêtre est au minimum de 800px alors la source est "aravis_grand.jpg"
SINON la source est "aravis_petit.jpg".
Remarquez que la balise PICTURE doit contenir les éléments SOURCE et IMG. La balise IMG précise la source de l'image si le test est faux.
L'image "aravis_grand.jpg" pèse 1200 Ko et est en haute résolution (2600 par 1500) alors que "aravis_petit.jpg" ne pèse que 70 Ko (600 par 400).

Cette technologie est assez lourde et doit être réservée à quelques images qui doivent s'afficher plein écran sur les grands écrans.

Pour en savoir plus sur la nouvelle balise PICTURE : HTML5 : balise PICTURE

Responsive Design et les images vectorielles

Pour que les images vectorielles (format SVG) produites avec un éditeur de textes (ou avec Inkscape ou les deux) ne soient jamais rognées sur un petit écran il suffit de modifier certains attributs de la balise SVG.

Imaginons qu'avec Inkscape vous avez créé un document de 600 par 400 pixels.
Dans le code de la balise SVG ouvrante on avait entre autres : ...width ="600" height="400"

Avant d'insérer cette image dans une page web il faut le modifier comme suit le code du fichier SVG :

<svg ... width ="80%" height="auto" viewBox ="0 0 600 400" >

J'ai changé les valeurs des attributs width & height et j'ai rajouté l'attribut viewbox.

La taille de l'image SVG s'adapte ainsi à la largeur de l'écran. Mais pour que les formes contenues dans l'image vectorielle puissent toujours être dessinées il faut impérativement un système de coordonnées d'où l'ajout de l'attribut viewBox.
Les deux dernières valeurs du viewBox correspondent aux anciennes valeurs des attributs width et height.

Responsive design et canvas

L'API Canvas vous permet de produire un dessin (statique ou animé) matriciel dans une page web.
Même problématique qu'avec une image vectorielle SVG : la zone de dessin Canvas doit s'afficher proprement même sur un petit écran.
Il suffit de définir une taille "officielle" du canevas avec les attributs width / height de la balise CANVAS puis de définir les dimensions d'affichage du canevas via une règle de style : propriétés CSS width / height).
Exemple :

<canvas width ="600" height ="400" style ="width :80% ; height : auto ;"></canvas>

La zone de dessin CANVAS va s'afficher conformément au CSS (largeur du canevas = 80%) mais pour le script la zone de dessin fait 600px par 400px.
Donc les instructions canvas.width & canvas.height retournent respectivement : 600 & 400 et les formes sont dessinées en fonction de ce repère cartésien.

Media queries et display gridlayout / flex

Dans le cadre d'un CSS moderne je vous conseille d'abonner l'outil "float" pour positionner les boites au profit des technologies introduites par la version 3 : outils grid-layout et flexbox.
Retour menu