Dans ce chapitre, on va aborder une notion essentielle en CSS : le responsive design. L'objectif de cette pratique consiste à faire en sorte qu'un site s'adapte correctement à tous les types de périphérique (écran, tablette, mobile...).
Quand on avait intégré notre première maquette, on ne s'était pas préoccupé de cela. Le résultat, c'est qu'en réduisant la fenêtre, le site déborde de l'écran et fait apparaitre des barres de navigations et rend la lecture du site quasi impossible.
La balise viewport
La première étape pour un site responsive se joue dans le HTML.
Dans le <head>, on trouve généralement cette balise :
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
Elle indique au navigateur que la largeur de la page doit correspondre à la largeur du périphérique.
Sans cela, le rendu mobile peut être très différent de ce que l'on attend.
max-width et min-width
Une des premières erreurs fréquentes consiste à fixer une largeur rigide sur un conteneur.
Par exemple :
.container {
width: 1120px;
}
Cela fonctionne très bien sur un grand écran, mais dès que la fenêtre devient plus petite, tout déborde.
Dans ce cas, on préférera :
.container {
max-width: 1120px;
}
max-width permet un comportement hybride. Si il y a suffisamment d'espace, l'élément sera contraint à une largeur de 1120px. En revanche, si l'espace du parent est trop réduit, il reviendra au comportement automatique et occupera 100% de l'espace.
Ce max-width est souvent accompagné de marge intérieur et extérieur :
.container {
max-width: 1120px;
padding-inline: 1rem; /* On évite que le contenu soit collé au bord de l'écran */
margin-inline: auto; /* L'élément se centre si l'écran est assez large */
}
Le même principe existe aussi pour la hauteur avec :
min-heightmax-height
Les media queries
Même avec des largeurs flexibles, cela ne suffit pas toujours. Dans certains cas la disposition des élément doit changer complètement et c'est là qu'interviennent les media queries.
Une media query permet d'appliquer du CSS seulement si une condition particulière est remplie. La syntaxe de base est la suivante :
@media (min-width: 500px) {
body {
background: lightgray;
}
}
Ici, le CSS contenu dans le bloc ne s'applique que si la largeur de l'écran est d'au moins 500px. On peut faire l'inverse avec :
@media (max-width: 500px) {
body {
background: lightgray;
}
}
Cette fois, les règles ne s'appliquent que si l'écran est plus petit que 500px.
min-width ou max-width ?
Ces deux approches correspondent en réalité à deux manières différentes de penser le responsive.
L'approche mobile-first
Dans une approche mobile-first, on commence par écrire le CSS pour les petits écrans, puis on ajoute des règles pour les écrans plus larges.
On utilise alors surtout min-width.
.header {
flex-direction: column;
}
@media (min-width: 750px) {
.header {
flex-direction: row;
}
}
L'approche desktop-first
Dans une approche desktop-first, on écrit d'abord le CSS pour le bureau, puis on corrige pour les petits écrans.
On utilise alors plutôt max-width.
En pratique, on a souvent tendance à préférer le mobile-first, car un design mobile est généralement plus simple que la version grand écran. Cette approche permet d'écrire moins de règles qui viendraient écraser les précédentes.
Les grilles responsives
Le responsive devient particulièrement intéressant avec les grilles.
Prenons une liste de cartes produits. Sur mobile, une seule colonne suffit souvent :
.products {
display: grid;
}
Puis, sur un écran un peu plus grand :
@media (min-width: 750px) {
.products {
grid-template-columns: repeat(2, 1fr);
}
}
Et sur un écran encore plus large :
@media (min-width: 900px) {
.products {
grid-template-columns: repeat(3, 1fr);
}
}
De cette manière, on adapte progressivement le nombre de colonnes.
Masquer un élément avec display: none
Dans certains cas, on peut vouloir masquer un élément sur une taille intermédiaire.
Par exemple :
@media (min-width: 750px) {
.product:nth-child(3) {
display: none;
}
}
Et plus tard, le réafficher :
@media (min-width: 900px) {
.product:nth-child(3) {
display: block;
}
}
display: none retire complètement l'élément de l'affichage : il n'a plus de largeur ni de hauteur visibles.
Ce n'est pas quelque chose qu'on utilisera partout, mais cela peut parfois permettre de simplifier une mise en page sur certaines tailles.
Quelques ajustements fréquents
Dans une logique responsive, on change souvent :
- la direction d'un
flex - le nombre de colonnes d'une grille
- la taille de certains textes (titres par exemple)
- les espacements
- certains alignements
Par exemple, un grand titre peut être plus discret sur mobile :
.hero-title {
font-size: 3rem;
}
@media (min-width: 750px) {
.hero-title {
font-size: 5rem;
}
}
Le principe est toujours le même : on commence par une version simple, puis on enrichit le design à mesure que l'espace augmente.
print et screen
Les media queries ne servent pas uniquement au responsive lié à la largeur. On peut aussi cibler un contexte d'affichage particulier :
@media print {
.logo {
font-size: 20cm;
}
}
Ici, les règles ne s'appliquent qu'au moment de l'impression. Et à l'inverse :
@media screen {
.logo {
font-size: 5rem;
}
}
On peut aussi définir les media query lors de l'import d'un fichier CSS :
<link rel="stylesheet" href="print.css" media="print" />
Cela permet d'avoir une feuille de style spécifique à l'impression.
L'orientation
Il existe aussi des media queries liées à l'orientation du périphérique :
@media (orientation: landscape) {
/* ... */
}
Ou :
@media (orientation: portrait) {
/* ... */
}
Cela peut être utile dans certains cas, notamment sur tablette ou sur mobile, même si c'est moins courant que les media queries sur la largeur.
Le responsive des images
Le responsive ne se limite pas au CSS. Pour les images, HTML propose aussi des mécanismes permettant de charger une image différente selon la taille de l'écran.
Cela passe notamment par des attributs comme srcset, qui permettent de proposer plusieurs variantes d'une même image.
Ce n'est pas directement du CSS, mais c'est un point important à garder en tête quand on travaille sur des interfaces réellement responsives.