Retour au blog
sept. 2026·3 min de lectureGénéré par IA
Langue:DeutschEnglishFrançaisÖsterreichischKlingonian Version originale: English

CSS Container Queries : un guide pratique

#css#frontend

Les media queries répondent à une seule question : quelle est la taille du viewport ? C'est la mauvaise question pour la plupart des composants, car une carte, un widget de barre latérale ou une vignette produit se moque de la largeur de la fenêtre du navigateur : ce qui compte, c'est la place dont il dispose, et elle dépend de l'endroit où il est placé dans la mise en page. Les container queries répondent à la question dont les composants ont réellement besoin.

Le problème du responsive design basé uniquement sur les media queries

Imaginons un composant <card> qui doit passer d'une disposition horizontale à une disposition verticale lorsqu'il devient étroit. Avec des media queries, vous devez deviner la largeur de viewport à laquelle cela se produit :

.card {
  display: flex;
  flex-direction: row;
}

@media (max-width: 500px) {
  .card {
    flex-direction: column;
  }
}

Cela fonctionne très bien si la carte occupe toujours presque toute la largeur du viewport. Mais placez cette même carte dans une barre latérale étroite sur un écran de bureau de 1400 px, et elle n'obtient jamais la disposition verticale dont elle a besoin : le viewport est immense, alors que la place disponible pour la carte est minuscule. L'apparence du composant dépend de quelque chose qu'il ne contrôle pas : l'endroit où son parent décide de le placer.

Déclarer un contexte de confinement

Les container queries inversent la question : au lieu de « quelle est la largeur du viewport ? », vous demandez « quelle est la largeur de mon ancêtre le plus proche qui a choisi d'être un conteneur de requêtes ? ». On active ce choix sur un élément avec container-type :

.card-grid {
  container-type: inline-size;
  container-name: card-grid;
}

inline-size signifie « suivre la largeur du conteneur » (le cas habituel pour les décisions de mise en page horizontale). container-name est facultatif : il permet de cibler un conteneur ancêtre précis lorsque plusieurs conteneurs sont imbriqués, au lieu d'interroger simplement « le plus proche ».

Interroger le conteneur

Une fois le confinement déclaré, les descendants peuvent interroger la taille de ce conteneur plutôt que celle du viewport :

.card {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

@container card-grid (min-width: 400px) {
  .card {
    flex-direction: row;
    gap: 16px;
  }
}

Désormais, le même composant .card passe en disposition horizontale dès qu'il dispose d'au moins 400 px de largeur de conteneur, qu'il soit seul sur une page large ou l'une des trois colonnes d'une page plus étroite. Le composant réagit à sa place réelle, et non à une valeur de viewport qui peut n'avoir aucun rapport.

Les unités de container queries

À côté de @container, il existe un jeu d'unités de longueur qui se résolvent par rapport au conteneur de requêtes et non au viewport : cqw, cqh, cqi, cqb, cqmin, cqmax (sur le modèle de vw/vh/vmin/vmax, mais relatives au conteneur). C'est utile pour une typographie fluide qui doit suivre la boîte du composant plutôt que la page entière :

.card-title {
  font-size: clamp(14px, 5cqi, 22px);
}

5cqi correspond à 5 % de la taille en ligne du conteneur : le titre grandit donc quand la carte s'élargit, borné entre 14 px et 22 px, indépendamment de la largeur du viewport.

Un piège fréquent : interroger son propre conteneur

container-type établit le confinement sur un élément, et les requêtes @container regardent l'ancêtre le plus proche qui a ce confinement : un élément ne peut pas s'interroger lui-même :

/* This does NOT work as you might expect */
.card {
  container-type: inline-size;
}

@container (min-width: 400px) {
  .card {
    /* .card can't query the container-type it declares on itself */
  }
}

La solution est le schéma de l'exemple précédent : mettre container-type sur le parent (.card-grid) et l'interroger depuis les enfants (.card). Cela déroute, car c'est l'inverse de ce qu'on fait naturellement : on veut que la carte réagisse à sa propre taille, mais le confinement doit se trouver un niveau plus haut.

Support navigateur et solution de repli

Les container queries sont bien prises en charge dans les versions actuelles de Chrome, Firefox, Safari et Edge. Pour tout ce qui doit fonctionner sur de très vieux navigateurs, @supports permet de prévoir une solution de repli avec des media queries :

.card {
  flex-direction: column;
}

@media (min-width: 700px) {
  .card {
    flex-direction: row;
  }
}

@supports (container-type: inline-size) {
  @media (min-width: 700px) {
    .card {
      flex-direction: column; /* undo the media-query version */
    }
  }

  .card-grid {
    container-type: inline-size;
  }

  @container (min-width: 400px) {
    .card {
      flex-direction: row;
    }
  }
}

À retenir

Les media queries décrivent le viewport ; les container queries décrivent la place réellement disponible pour le composant, ce qui est presque toujours ce que l'on voulait demander au départ. Si vous avez déjà écrit un composant qui s'affiche bien en haut de la page et mal dès qu'il est réutilisé dans une barre latérale, voilà exactement le problème que les container queries résolvent.

Plus récentCréer un hook personnalisé de récupération de données en ReactPlus ancienComment fonctionne réellement le DOM virtuel