Essayer de coder ← Retour aux sujets

Viewport et media queries

@media

Un site responsive s'adapte à toutes les tailles d'écran. Deux ingrédients : la balise viewport (en HTML) et les media queries (en CSS).

<meta name="viewport" content="width=device-width, initial-scale=1">
Indispensable : sans elle, le téléphone affiche une page « dézoomée »
@media (min-width: 768px) { … }
S'applique à partir de 768 px de large (approche mobile first)
@media (max-width: 600px) { … }
S'applique jusqu'à 600 px de large
@media (orientation: landscape) { … }
Écran en mode paysage
@media (prefers-color-scheme: dark) { … }
L'utilisateur a choisi un thème sombre
@media (prefers-reduced-motion: reduce) { … }
L'utilisateur demande moins d'animations
responsive.css
.grille {
  display: grid;
  gap: 1rem;
  grid-template-columns: 1fr;
}

@media (min-width: 768px) {
  .grille {
    grid-template-columns: 1fr 1fr;
  }
}

@media (min-width: 1100px) {
  .grille {
    grid-template-columns: repeat(3, 1fr);
  }
}
Rendu
Une colonne sur téléphone, deux colonnes sur tablette, trois colonnes sur grand écran.

Unités et images fluides

fluide

Plutôt que des tailles fixes en pixels, on emploie des unités qui s'ajustent : pourcentages, rem, vw, min(), clamp().

max-width: 100%; height: auto;
Une image ne dépasse jamais son conteneur
width: min(100% - 2rem, 60rem);
Presque toute la largeur, mais jamais plus de 60rem
font-size: clamp(1rem, 2.5vw, 1.5rem);
Texte qui grandit avec l'écran, entre deux bornes
padding: clamp(1rem, 4vw, 3rem);
Marges intérieures adaptatives
repeat(auto-fit, minmax(14rem, 1fr))
Colonnes qui s'adaptent sans media query
flex-wrap: wrap;
Passer à la ligne au lieu de déborder
fluide.css
img {
  max-width: 100%;
  height: auto;
}

.conteneur {
  width: min(100% - 2rem, 60rem);
  margin-inline: auto;
}

h1 {
  font-size: clamp(1.75rem, 4vw + 1rem, 3rem);
}
Rendu
Les images se réduisent avec leur conteneur ; le contenu reste centré avec 1 rem de marge de chaque côté et 60 rem au plus ; le titre grandit de 1,75 rem à 3 rem selon l'écran.

📱 Le cours : une page pour tous les écrans

Une grande partie des visites se fait aujourd'hui sur téléphone, et le même site doit rester agréable sur un ordinateur de bureau ou une tablette. On n'écrit pas trois sites : on écrit une page qui s'adapte. C'est le *responsive design*.

La balise viewport

Par défaut, un téléphone suppose que les pages sont conçues pour un grand écran et les affiche « dézoomées ». La balise <meta name="viewport" content="width=device-width, initial-scale=1">, placée dans le <head>, dit au navigateur d'utiliser la vraie largeur de l'appareil. Sans elle, aucune media query ne se comportera comme prévu sur mobile (voir Structure).

Mobile first

L'approche recommandée : écrire d'abord le CSS pour le plus petit écran (une colonne, des éléments empilés), puis ajouter des règles avec min-width quand l'écran s'élargit. Le code de base reste léger et simple, et un appareil qui ne comprend pas les media queries obtient quand même une page correcte.

Les media queries

@media (condition) { règles } applique les règles seulement si la condition est vraie. Les conditions les plus courantes :

ConditionSe lit
(min-width: 768px)écran large d'au moins 768 px
(max-width: 600px)écran large d'au plus 600 px
(min-width: 600px) and (max-width: 900px)entre 600 et 900 px
(orientation: landscape)plus large que haut
(hover: hover)l'appareil sait survoler (souris), pas un écran tactile
printà l'impression

Les largeurs de rupture (*breakpoints*) classiques sont proches de 576, 768, 1024 et 1280 px, mais le meilleur critère est ton contenu : ajoute une rupture là où la mise en page casse, pas à des valeurs apprises par cœur.

Un menu qui s'adapte

Exemple type : un menu empilé sur téléphone, en ligne à partir de la tablette.

menu.css
.menu {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

@media (min-width: 768px) {
  .menu {
    flex-direction: row;
    gap: 1.5rem;
  }
}

Des dimensions fluides

  • Évite les largeurs fixes en pixels pour les conteneurs : width: 960px provoque un défilement horizontal sur téléphone. Préfère max-width (une limite) et width: 100%.
  • Les images : max-width: 100%; height: auto; les empêche de dépasser (voir aussi srcset dans Médias).
  • Les grilles et rangées : flex-wrap: wrap et repeat(auto-fit, minmax(…)) s'adaptent sans media query (voir Grid).
  • Les tailles de texte : rem pour respecter les réglages de l'utilisateur, clamp(min, préféré, max) pour une taille qui évolue en douceur avec l'écran.

Respecter les préférences de l'utilisateur

Le navigateur connaît des choix faits dans le système : thème sombre, réduction des animations. Une media query permet d'en tenir compte. Avec des variables CSS (voir Pseudo-classes et variables), le thème sombre se règle en quelques lignes :

theme.css
:root {
  --fond: #ffffff;
  --texte: #14141a;
}

@media (prefers-color-scheme: dark) {
  :root {
    --fond: #14141a;
    --texte: #f7f2ea;
  }
}

body {
  background: var(--fond);
  color: var(--texte);
}

Tester sa page

  • Dans le navigateur, F12 puis le mode appareil (Ctrl + Maj + M) simule un téléphone et permet de choisir la largeur.
  • Redimensionne la fenêtre à la main : repère où la mise en page casse, ajoute une rupture à cet endroit.
  • Teste le zoom à 200 % et, si possible, un vrai téléphone : la taille des zones tactiles se juge au doigt (au moins 44 px de côté).

⚠️ Erreurs fréquentes

Oublier la balise viewport

Sans elle, les media queries sur mobile semblent « ne pas marcher » : le téléphone croit avoir un écran de 980 px. Vérifie qu'elle est présente dans le <head> de chaque page.

Des largeurs fixes en pixels

À éviter
faux.css
.page { width: 960px; }                 /* défilement horizontal sur téléphone */
Correct
correct.css
.page { width: 100%; max-width: 60rem; }  /* souple, avec une limite */

Utiliser 100vw pour une largeur de page

100vw inclut la barre de défilement verticale : une page qui défile devient un peu trop large et fait apparaître un défilement horizontal. Préfère 100%.

Mélanger max-width et min-width sans cohérence

Si un côté de la page utilise max-width: 768px et l'autre min-width: 768px, à exactement 768 px les deux s'appliquent. Choisis une approche (de préférence min-width) et tiens-t'y.

Cacher du contenu sur mobile

Un display: none systématique sur petit écran prive les utilisateurs mobiles d'une partie du contenu. Réorganise (empile, replie dans un volet <details>) plutôt que de supprimer.

Des zones tactiles trop petites

Un lien ou un bouton de 20 px est difficile à viser au doigt. Garde au moins 44 × 44 px pour les éléments cliquables, avec de l'espace entre eux.

Un texte de formulaire trop petit sur iPhone

Avec une taille de police inférieure à 16 px, certains navigateurs mobiles zooment automatiquement dès qu'on touche un champ. Mets font-size: 1rem (16 px) au minimum dans les champs.

📋 Aide-mémoire

  • HTML : <meta name="viewport" content="width=device-width, initial-scale=1"> dans chaque page.
  • Mobile first : CSS de base pour petit écran, puis @media (min-width: …) pour agrandir.
  • Ruptures : là où la mise en page casse (≈ 576, 768, 1024, 1280 px) ; (prefers-color-scheme), (prefers-reduced-motion), (orientation).
  • Fluide : max-width: 100%; height: auto; (images), width: min(100% - 2rem, 60rem), clamp(min, préféré, max), flex-wrap: wrap, repeat(auto-fit, minmax(…)).
  • Unités : rem et % plutôt que px ; 100% plutôt que 100vw.
  • Tester avec F12 (mode appareil), au zoom 200 % et sur un vrai téléphone ; zones tactiles d'au moins 44 px.