CSS Container Queries : adapter un composant à son conteneur
Rendez un composant responsive selon l’espace qu’il reçoit réellement, plutôt que selon la largeur de toute la fenêtre.
Où en êtes-vous avec cette notion ?
Une indication personnelle, enregistrée uniquement dans ce navigateur.
À lire ensuite
Le format café
L’essentiel à comprendre, le temps d’un café.
Envie de creuser ? Un cours plus complet vous attend juste après, à déplier sans quitter cette page.
L’idée intuitive
Une media query pose généralement la question : « quelle est la largeur de la fenêtre ? ». Mais un composant réutilisable a souvent besoin d’une autre information : « combien de place ai-je ici ? ».
Une même carte peut être large dans le contenu principal et étroite dans une barre latérale, alors que le navigateur n’a pas changé de taille.
Fenêtre 1200 px
┌───────────────────────────────┬───────────┐
│ zone principale │ sidebar │
│ ┌─────────────────────────┐ │ ┌───────┐ │
│ │ carte large │ │ │ carte │ │
│ └─────────────────────────┘ │ └───────┘ │
└───────────────────────────────┴───────────┘
Les container queries permettent au CSS d’adapter chaque carte à la taille de son propre conteneur.
Déclarer un conteneur
On commence par indiquer quel élément fournit le contexte de taille :
.card-zone {
container-type: inline-size;
}
inline-size signifie que les requêtes pourront raisonner sur la dimension dans l’axe du texte — en français horizontal, essentiellement la largeur.
Faire réagir le composant
La carte possède d’abord une mise en page qui fonctionne dans un petit espace :
.card {
display: grid;
gap: 1rem;
}
Puis on l’enrichit quand son conteneur devient assez large :
@container (width >= 36rem) {
.card {
grid-template-columns: 12rem 1fr;
}
}
Le navigateur cherche le plus proche ancêtre compatible avec cette requête. Si sa largeur atteint 36 rem, la carte passe sur deux colonnes.
Le composant ne connaît ni la page, ni la sidebar, ni la taille de l’écran. Il connaît seulement l’espace qu’on lui donne.
Nommer le conteneur quand la page devient complexe
Pour éviter qu’une requête utilise un autre conteneur imbriqué par erreur, on peut le nommer :
.card-zone {
container: cards / inline-size;
}
@container cards (width >= 36rem) {
.card {
grid-template-columns: 12rem 1fr;
}
}
Le nom cards rend la relation explicite.
Le piège important
Les règles d’une @container s’appliquent aux descendants du conteneur interrogé, pas au conteneur lui-même. Et déclarer un conteneur de taille introduit du containment : sa taille doit pouvoir être déterminée par son contexte plutôt que dépendre uniquement de son contenu.
Pour la plupart des composants responsives horizontalement, container-type: inline-size est le choix le plus simple.
Fiche mémo
- Media query : adapte selon la fenêtre ou le périphérique.
- Container query : adapte selon l’espace du composant.
container-type: inline-sizecrée un contexte de requête horizontal.@container (width >= ...)applique des styles aux descendants quand la condition devient vraie.- Un nom de conteneur évite les ambiguïtés dans les interfaces imbriquées.
L’idée à emporter : les container queries rendent un composant réellement réutilisable : il s’adapte à la place qu’il obtient, pas à l’endroit où vous aviez imaginé le placer.
Et si on allait plus loin ?
Le café vous a donné les repères. Prenez maintenant le temps de comprendre les mécanismes et de pratiquer, si vous le souhaitez.
Aller plus loinConcevoir des composants responsives indépendants de la pageDévelopper le coursReplier le cours
Ce que vous saurez faire
Choisir entre media query et container query, nommer un contexte dans une interface imbriquée et utiliser les unités relatives au conteneur sans rendre le composant fragile.
1. Le breakpoint appartient au composant
Une media query est pertinente quand la composition globale dépend de la fenêtre : navigation mobile, nombre de colonnes d’une page, préférences du périphérique, etc.
Une container query devient plus naturelle quand la règle appartient au composant :
.product-slot {
container: product / inline-size;
}
.product-card {
display: grid;
gap: 1rem;
}
@container product (width >= 30rem) {
.product-card {
grid-template-columns: minmax(8rem, 12rem) 1fr;
align-items: start;
}
}
Cette carte peut maintenant vivre dans une grille, une modale ou une colonne secondaire sans que son CSS contienne un breakpoint lié à la largeur de la page.
Référence : MDN — CSS container queries.
2. Pourquoi inline-size est souvent préférable à size
container-type: size permet d’interroger les deux dimensions, largeur et hauteur. Il applique aussi un containment de taille dans les deux axes : le navigateur doit pouvoir calculer la taille du conteneur indépendamment de ses enfants.
Pour un composant qui ne réagit qu’à l’espace horizontal, inline-size est généralement plus adapté : il limite le containment à cet axe et répond directement au besoin.
La taille du conteneur doit néanmoins provenir du contexte — par exemple un bloc qui s’étire dans sa colonne, une piste de grille ou une largeur explicite. Avec du size containment et aucune taille déterminable, un élément peut se retrouver sans la dimension que son contenu lui aurait normalement donnée.
Référence : MDN — container-type.
3. Les noms évitent les mauvaises correspondances
Dans un composant imbriqué, plusieurs ancêtres peuvent être des query containers. Sans nom, le navigateur utilise le plus proche qui convient au type de requête.
.dashboard {
container: dashboard / inline-size;
}
.widget-list {
container: widgets / inline-size;
}
@container widgets (width >= 40rem) {
.widget-card {
grid-template-columns: 1fr 1fr;
}
}
Le nom widgets documente précisément la dimension à laquelle la carte doit répondre. C’est particulièrement utile lorsqu’un composant possède lui-même des sous-composants responsives.
4. Les unités cqi suivent le conteneur
CSS fournit aussi des unités relatives au query container. 1cqi représente 1 % de sa taille dans l’axe inline.
@container product (width >= 24rem) {
.product-card h2 {
font-size: clamp(1.1rem, 1rem + 2cqi, 1.8rem);
}
}
Le titre peut ainsi évoluer doucement avec l’espace réellement disponible, tout en restant borné par clamp().
Ne transformez pas toutes les dimensions en unités de conteneur. Les tailles de police de base, espacements et zones tactiles ont souvent intérêt à rester stables ; utilisez les unités cq* lorsque la relation avec la taille du composant apporte réellement quelque chose.
5. Construire d’abord une base robuste
Une container query doit améliorer un composant déjà utilisable dans son état par défaut :
.card {
display: grid;
gap: 1rem;
}
@container cards (width >= 36rem) {
.card {
grid-template-columns: 12rem 1fr;
}
}
La première règle reste valide dans un espace étroit. La requête ne sert qu’à changer la composition quand davantage de place existe. Cette progression rend le composant plus prévisible et simplifie aussi la prise en charge d’environnements plus anciens lorsque celle-ci compte pour votre projet.
Pièges importants
- Ne choisissez pas les seuils à partir de modèles de téléphone : choisissez-les au moment où le composant a réellement assez d’espace pour changer de composition.
- Une requête de taille nécessite un conteneur de taille compatible ; un simple
container-namene suffit pas pour interroger sa largeur. - Les styles de la requête ciblent les descendants du conteneur interrogé, pas ce conteneur lui-même.
sizeajoute plus de contraintes queinline-size; ne l’utilisez que si vous devez réellement interroger les deux axes.- Les container queries complètent les media queries : elles ne les rendent pas obsolètes.
Mémo final
Utilisez les media queries pour les décisions qui appartiennent à la page ou au périphérique. Utilisez les container queries pour les décisions qui appartiennent au composant. Cette séparation produit des composants plus autonomes, plus faciles à déplacer et plus proches de la logique réelle d’un design system.
Vous pouvez aussi vous arrêter ici. L’approfondissement est facultatif.
Les repères Cours Café
Pour aller à la source
Documentation de référence. Vérification éditoriale encore à effectuer.
Gardez une trace de cette idée.
Favoris, notes et progression seront disponibles après connexion du stockage distant.