Adloun

Responsive design

Cours · CSS : mettre en forme le Web (école d'ingénieur), chapitre 9 · école d'ingénieur, informatique · le début du chapitre, la suite sur Adloun

Ouvrons la Librairie du Campus, telle que le chapitre 8 l'a laissée, sur un téléphone. La colonne des services, fixée à 16rem, prend les deux tiers de l'écran ; les nouveautés s'écrasent dans ce qui reste ; sur la page d'un livre, la couverture de 256 pixels ne laisse au résumé qu'une bande de quelques mots. La mise en page a été pensée pour un écran d'ordinateur, et seulement pour lui.

Plus de la moitié des visites d'un site grand public se font aujourd'hui depuis un téléphone. Le responsive design (conception adaptative) consiste à écrire une seule page, avec une seule feuille de style, qui s'adapte à toutes les largeurs d'écran — et, plus largement, aux préférences du visiteur : thème sombre, animations réduites, impression.

Objectifs du chapitre

  • Comprendre le rôle de la balise <meta name="viewport">.
  • Écrire une feuille « mobile d'abord », avec des requêtes média @media (width >= 48rem) et la syntaxe d'intervalle.
  • Calculer des tailles fluides avec clamp() et les unités de la fenêtre (vw, dvh).
  • Rendre les images souples et laisser le navigateur choisir la bonne résolution (srcset, sizes).
  • Adapter un composant à la place dont il dispose, avec les requêtes de conteneur (@container).
  • Respecter les préférences du visiteur : prefers-color-scheme, prefers-reduced-motion, et l'impression.
  • Tester avec le mode « appareil » des outils de développement.

9.1 La fenêtre d'affichage d'un téléphone

Les premiers smartphones (l'iPhone, en 2007) devaient afficher des sites conçus pour des écrans de 1000 pixels. Leur astuce : faire comme si l'écran mesurait 980 pixels de large, mettre la page en forme à cette largeur, puis la réduire pour qu'elle tienne dans l'écran. Le visiteur zoome ensuite avec les doigts. Les téléphones font toujours ainsi… sauf si la page dit qu'elle sait s'adapter.


<meta name="viewport" content="width=device-width, initial-scale=1">
Définition 9.1Fenêtre d'affichage

La fenêtre d'affichage (viewport) est la zone où la page est mise en forme ; c'est sa largeur que testent les requêtes média et que mesure l'unité vw. La balise <meta name="viewport"> demande qu'elle ait la largeur de l'écran de l'appareil, mesurée en pixels CSS (device-width), sans zoom initial (initial-scale=1).

Nous l'avons vérifié en simulant dans Chromium un téléphone de 375 pixels de large. Sans la balise, la page est mise en forme sur 980 pixels (document.documentElement.clientWidth vaut 980) et affichée à l'échelle 0,38 : le texte devient illisible, et une requête média prévue pour les écrans de moins de 768 pixels ne s'applique pas, puisque la fenêtre en mesure 980. Avec la balise, la fenêtre mesure 375 pixels, à l'échelle 1.

Toutes les pages du livre HTML avaient déjà cette balise : c'est l'une des lignes à ne jamais oublier.

Attention — ne bloquez pas le zoom

On trouve encore des pages qui écrivent maximum-scale=1 ou user-scalable=no pour empêcher le zoom. C'est une faute d'accessibilité : un visiteur malvoyant ne peut plus agrandir le texte. Les navigateurs récents ignorent d'ailleurs souvent ces valeurs.

9.1.1 Pixels CSS et pixels de l'écran

Un téléphone de 375 pixels CSS a souvent un écran de 750 ou 1125 pixels physiques : chaque pixel CSS est dessiné par 2 × 2 ou 3 × 3 points. Ce rapport s'appelle le ratio de pixels (devicePixelRatio). Pour la mise en page, il est invisible : on raisonne toujours en pixels CSS. Il compte pour les images (une image de 375 pixels serait floue sur un écran de ratio 3) : nous y reviendrons.

9.2 Les requêtes média

Définition 9.2Requête média

Une requête média @media (condition) { /* règles */ } n'applique les règles qu'elle contient que si la condition est vraie pour l'appareil : largeur de la fenêtre, orientation, préférences du visiteur, type de média (écran ou impression). Elle ne change pas la spécificité des règles : à spécificité égale, c'est toujours l'ordre dans la feuille qui départage.

La condition la plus utilisée porte sur la largeur de la fenêtre. Depuis 2023, tous les navigateurs comprennent la syntaxe d'intervalle, plus lisible que l'ancienne :

syntaxe d'intervalleancienne syntaxe
(width >= 48rem)(min-width: 48rem)
(width < 48rem)(max-width: 47.99rem)
(30rem <= width < 50rem)(min-width: 30rem) and (max-width: 49.99rem)

L'ancienne syntaxe ne connaît que les bornes incluses. Si l'on écrit (max-width: 768px) pour les petits écrans et (min-width: 768px) pour les grands, les deux requêtes sont vraies à 768 pixels exactement ; l'exercice 9.11 montre le défaut qui en résulte. La syntaxe d'intervalle exprime < et >= sans ambiguïté.

9.2.1 Mobile d'abord

On peut écrire une feuille pour grand écran, puis la corriger pour les petits (requêtes en width <), ou l'inverse. La seconde méthode est la bonne.

Méthode — mobile d'abord (mobile first)

  • Hors de toute requête média, écrire la mise en page la plus simple : celle du téléphone, souvent une seule colonne, dans l'ordre du code HTML.
  • Élargir la fenêtre (mode appareil des outils de développement) jusqu'à ce que la page devienne laide : lignes de texte trop longues, grands vides, cartes étirées.
  • À cette largeur, ajouter une requête @media (width >= …) qui ajoute des colonnes. Recommencer.

Les points de rupture sont choisis par le contenu, pas par une liste d'appareils à la mode. Les requêtes s'écrivent dans l'ordre croissant : la dernière qui est vraie l'emporte.

Pourquoi dans ce sens ? Parce que la mise en page en une colonne est celle du flux normal : il n'y a presque rien à écrire. Les grands écrans ajoutent des règles (des colonnes, des marges) au lieu d'en défaire. Et un navigateur qui ne comprendrait pas une requête média affiche quand même une page lisible.

Pour la Librairie, deux points de rupture suffisent : 48rem (768 pixels, à partir duquel la fiche d'un livre peut mettre sa couverture à gauche) et 64rem (1024 pixels, à partir duquel l'accueil a la place d'une colonne de services).

Proposition 9.3rem dans une requête média

Dans la condition d'une requête média, 1rem vaut la taille de police par défaut du navigateur (16 pixels, sauf si le visiteur l'a modifiée), et non celle que la feuille donne à <html>.

C'est pour cela qu'on exprime les points de rupture en rem : un visiteur qui a réglé son navigateur sur une police de 24 pixels voit la mise en page tablette dès 1152 pixels de large, et non à 768, ce qui évite des colonnes trop étroites pour son texte agrandi.

9.2.2 L'accueil, mobile d'abord

Réécrivons les zones de l'accueil. Hors requête : une seule colonne, les zones dans l'ordre du code.


.accueil {
  display: grid;
  grid-template-areas:
    "titre"
    "chapeau"
    "nouveautes"
    "services";
  grid-template-columns: minmax(0, 1fr);
  column-gap: 2rem;
}

@media (width >= 64rem) {
  .accueil {
    grid-template-areas:
      "titre      titre"
      "chapeau    chapeau"
      "nouveautes services";
    grid-template-columns: minmax(0, 1fr) 16rem;
  }
}

La règle grid-area de chaque enfant ne change pas : on ne redessine que la carte des zones. La fiche d'un livre et les formulaires suivent le même modèle à partir de 48rem ; l'en-tête et le contenu principal y reçoivent aussi des marges plus généreuses (2rem au lieu de 1rem).

9.3 Des tailles fluides

Entre deux points de rupture, la page doit rester agréable. Les unités relatives à la fenêtre et les fonctions de comparaison permettent des tailles qui varient continûment avec la largeur.

unitévaut
1vw1 % de la largeur de la fenêtre
1vh1 % de la hauteur de la fenêtre
1dvh1 % de la hauteur actuelle (barres du navigateur mobile comprises ou non)
1svh, 1lvh1 % de la plus petite, de la plus grande hauteur possible
1cqi1 % de la largeur du conteneur (voir plus loin)

La suite du cours est sur Adloun

Le chapitre en entier, formules et figures comprises, avec le tuteur, les fiches, les QCM et les exercices.

Lire la suite du cours

En accès libre, sans inscription.

Exercices corrigés de ce chapitre

Lire la suite du cours →