Guide pratique des Container Queries : conception responsive axée sur les composants

Cet article vous a aidé ?

Vous connaissez ce bug. La grille de cartes « responsive » est parfaite sur votre portable, s’effondre dans une barre latérale,
et devient une œuvre d’art moderne tragique dans une fenêtre modale. Quelqu’un ajoute un panneau, et soudain votre
« breakpoint desktop » se déclenche dans une boîte de largeur mobile parce que le composant a été intégré dans un endroit étrange.

Les Container Queries corrigent la catégorie de défaillance où le viewport n’est pas le bon signal. En production,
le bon signal est généralement : « Combien d’espace cet élément a-t-il à l’instant ? » C’est la promesse.
La réalité : vous devez toujours le concevoir et l’exploiter comme des adultes.

Pourquoi existent les Container Queries (et quand elles ne conviennent pas)

Les media queries concernent le viewport. C’est correct lorsque votre mise en page est principalement au niveau de la page :
en-tête, contenu principal, barre latérale, pied de page. C’est fragile quand votre UI est un jeu de Lego :
des cartes dans des onglets dans un tiroir dans une grille dans une page.

Les Container Queries permettent à un composant de s’adapter selon la taille de son conteneur, pas de la fenêtre.
Cela signifie qu’une « ProductCard » peut s’afficher en ligne compacte dans une barre latérale étroite, et en
mise en page deux colonnes aérée dans une zone de contenu large — sans que le composant ait besoin de connaître
son emplacement.

Utilisez les container queries lorsque :

  • Vous créez des composants réutilisables utilisés dans plusieurs mises en page (dashboards, blocs CMS, design systems).
  • Votre mise en page inclut des panneaux redimensionnables, vues en split, barres latérales, tiroirs et grilles imbriquées.
  • Vous voulez que vos breakpoints décrivent des états de composant, pas des classes d’appareil.

N’utilisez pas les container queries lorsque :

  • Vous prenez des décisions vraiment liées au viewport (changement de navigation globale, mise à l’échelle typographique globale).
  • Votre composant n’est jamais embarqué et seul le viewport importe.
  • Vous pouvez le résoudre avec des mises en page flexibles (grid/flex) sans breakpoints du tout.

Avis tranché : utilisez les media queries pour le cadrage de la page, les container queries pour l’intérieur des composants.
Si vous inversez cela, vous créerez un système « responsive » que personne n’a demandé.

Faits intéressants et courte histoire

Un peu de contexte aide, car les container queries ressemblent à une petite fonctionnalité CSS, mais elles représentent en réalité
un changement dans la façon dont on modélise l’UI responsive. Voici des faits concrets à retenir :

  1. Les container queries ont été demandées pendant plus d’une décennie parce que les auteurs voulaient des composants modulaires sans dépendance aux breakpoints globaux.
  2. La difficulté n’était pas la syntaxe ; c’était d’éviter les cycles de layout (les styles dépendent de la taille ; la taille dépend des styles).
  3. Des polyfills « element query » précoces existaient, souvent basés sur des ResizeObserver et beaucoup de JS, et ils étaient fragiles en charge réelle.
  4. Les container queries modernes sont apparues d’abord dans les navigateurs basés sur Chromium, puis dans d’autres moteurs majeurs, après beaucoup de travail sur la spécification du containment.
  5. La spec lie les queries aux « query containers », qui doivent être établis explicitement via container-type (ou le raccourci container).
  6. Les unités des container queries (cqw, cqh, etc.) sont relatives au query container, pas au viewport, ce qui permet à la typographie du composant d’évoluer localement.
  7. Le containment existait avant les container queries comme fonctionnalité de performance ; les container queries ont rendu le containment courant.
  8. Les design systems ont accéléré l’adoption car une même « carte » peut apparaître dans une liste, une grille, un carrousel ou une barre latérale — chacune avec des largeurs différentes.

Une citation pour garder les pieds sur terre, dans un esprit fiabilité. Brian Kernighan a dit : « Debugging is twice as hard as writing the code. »
Si vous n’êtes pas sûr de la formulation exacte, considérez cela comme une idée paraphrasée et conduisez-vous en conséquence : rendez votre logique de container queries débogable.

Modèle mental : containment, query containers et portée

Les container queries ne sont pas « des media queries en plus petit ». Elles introduisent une nouvelle dépendance :
les styles d’un élément peuvent dépendre de la taille d’un ancêtre. Cela paraît simple jusqu’à ce que vous vous rappeliez
que la taille peut dépendre des styles. Les moteurs CSS n’aiment pas les paradoxes.

Concept clé 1 : un « query container » doit exister

Une container query ne fonctionne que s’il existe un ancêtre avec container-type défini.
Sans cela, vos règles @container ne correspondront jamais, et vous passerez la moitié de la journée
à accuser le mauvais fichier.

Concept clé 2 : le containment prévient les cycles

Quand vous définissez container-type: inline-size, vous dites au navigateur :
« Vous pouvez utiliser ma taille en ligne (typiquement la largeur) pour les queries, et j’accepte les implications de containment. »
Le navigateur peut alors calculer les tailles dans un ordre qui n’engendre pas de boucle.

Si vous interrogez largeur et hauteur sans précaution, ou si vous laissez le layout dépendre de la taille du contenu de façon circulaire,
vous pouvez créer des mises en page instables. La plupart du temps, vous évitez le pire en n’interrogeant que l’inline size.
C’est le choix 80/20.

Concept clé 3 : la portée est locale, les noms aident

Les containers peuvent être nommés, et vous devriez les nommer lorsque votre page a plusieurs ancêtres possibles.
Sinon vous interrogez accidentellement le container le plus proche et vous vous demandez pourquoi votre composant change de mise en page
quand quelqu’un l’entoure avec un nouveau div.

Blague #1 : Les container queries sont comme des organigrammes — tout a du sens jusqu’à ce que quelqu’un ajoute une couche de « wrapping » et que personne ne sache qui relève de qui.

Syntaxe de base que vous utiliserez réellement

Définir un query container

Utilisez le raccourci quand vous le pouvez ; cela documente l’intention.
Le motif le plus courant consiste à faire du wrapper du composant le query container.

cr0x@server:~$ cat container-queries.css
/* Query container */
.widget {
  container-type: inline-size;
  container-name: widget;
}

/* Query by container width */
@container widget (min-width: 480px) {
  .widget .title { font-size: 1.25rem; }
  .widget .meta  { display: block; }
}

@container widget (max-width: 479px) {
  .widget .meta  { display: none; }
}

Ce qui compte : container-type: inline-size est l’outil par défaut.
Ne commencez pas par size sauf si vous avez une bonne raison d’interroger la hauteur aussi.

Containers nommés vs non nommés

Les containers non nommés fonctionnent, mais ils sont piégeux dans une bibliothèque de composants où les wrappers apparaissent et disparaissent.
Utilisez des noms pour la sérénité inter-équipes.

Unités de container query (la famille « cqw »)

Les unités de container query sont relatives à la taille du container :
1cqw est 1% de la largeur du query container,
1cqh est 1% de sa hauteur, etc.
Elles permettent de faire évoluer la typographie et les espacements selon l’espace disponible du composant.

Conseil pratique : utilisez les unités de container pour des ajustements subtils (padding, gap, typographie mineure).
Ne construisez pas un système complet de typographie fluide dans chaque composant. Là commence le chaos.

Patrons centrés sur le composant qui tiennent dans de vraies apps

Patron 1 : « La carte passe de pile à deux colonnes »

C’est la victoire canonique des container queries : une carte change de mise en page selon la largeur de son conteneur,
pas du viewport. Ça fonctionne dans les grilles, barres latérales, modales et panneaux partagés.

cr0x@server:~$ cat card.css
.card {
  container-type: inline-size;
  container-name: card;
  display: grid;
  gap: 12px;
}

.card__media { aspect-ratio: 16 / 9; background: #ddd; }
.card__body  { display: grid; gap: 8px; }

@container card (min-width: 520px) {
  .card {
    grid-template-columns: 220px 1fr;
    align-items: start;
  }
  .card__media { aspect-ratio: 1 / 1; }
}

Ce patron réduit votre dépendance aux breakpoints de page. La carte choisit sa mise en page
en fonction de l’espace. La page choisit les colonnes. Chacun reste dans son domaine.

Patron 2 : « Le tableau devient une liste de définitions dans les conteneurs étroits »

Les tableaux ne « répondent » pas bien. Dans des conteneurs étroits, changer de représentation est souvent préférable
à serrer les colonnes en fentes illisibles. Les container queries permettent que cette décision soit locale.

En pratique, conservez autant que possible le HTML sémantique. Vous pouvez toujours effectuer des changements de présentation en CSS :
masquer les en-têtes, afficher les lignes comme des blocs, ajouter des labels via data-label.
L’important est d’éviter les heuristiques liées au viewport. Le tableau dans la barre latérale ne doit pas prétendre être sur desktop.

Patron 3 : « La barre d’outils condense les actions dans un menu d’overflow »

Si vous avez déjà livré une toolbar qui se replie au mauvais moment, vous savez pourquoi les container queries comptent.
La toolbar doit réagir à sa propre largeur, pas à ce que fait la fenêtre.

Pour le comportement d’overflow réel, vous utiliserez probablement du JS (mesurer les enfants et les déplacer).
Les container queries vous donnent néanmoins des seuils stables pour passer de « afficher les labels »
à « icônes seulement » puis à « menu d’overflow ».

Patron 4 : « Composant qui s’adapte dans un panneau redimensionnable »

Les panneaux redimensionnables sont l’endroit où les breakpoints liés au viewport meurent.
Avec les container queries, le composant réagit en continu pendant que l’utilisateur glisse.
C’est du vrai UX, pas de la réactivité cochée sur une liste.

Patron 5 : « Conteneurs imbriqués : états de composant clairement empilés »

L’imbrication de containers est valide, mais c’est aussi ainsi que vous obtenez des comportements surprises quand un nouveau wrapper devient le container le plus proche.
Utilisez des noms de container et interrogez le bon. Si la mise en page d’un composant dépend d’un wrapper spécifique, nommez-le et ciblez-le.

Design systems : comment éviter la soupe de breakpoints

Les container queries sont de l’essence. Vous pouvez propulser une voiture de course ou mettre le feu au garage.
Les design systems sont l’endroit où cela compte : des dizaines de composants, des centaines de compositions, plusieurs équipes,
et un train de releases qui n’attend pas parce que le CSS est « presque correct ».

Choisissez des « classes de taille » de composant que vous saurez expliquer

Dans un design system, ne définissez pas de breakpoints comme des valeurs pixel aléatoires par composant.
Définissez un petit ensemble de seuils sémantiques par composant : compact, regular, spacious.
Mappez-les aux largeurs de conteneur. Documentez les comportements par état.

Si vous ne pouvez pas décrire un breakpoint sans mentionner un appareil, vous pensez probablement viewport.
Les container queries, c’est la pensée composant. Restez cohérent.

Rendez le conteneur explicite dans le contrat du composant

Décidez quel élément est le query container. Mettez-le dans l’API du composant et tenez-vous-y.
Si votre composant peut être utilisé seul, il devrait créer son propre container.
S’il doit hériter d’un container, documentez la contrainte — et attendez-vous à ce qu’elle soit violée à 2h du matin.

Privilégiez moins de queries et des primitives de layout plus fortes

Utilisez grid/flex et sizing intrinsèque d’abord. Ensuite appliquez les container queries pour quelques changements de forme significatifs.
Si chaque 40px de largeur change quelque chose, vous avez créé un test d’intégration continue pour la patience humaine.

Stratégie de test : snapshots de mise en page à la largeur du composant, pas du viewport

Vos tests devraient rendre le composant à des largeurs de conteneur représentatives :
320, 420, 520, 720, etc. Ces nombres sont des exemples ; choisissez ceux qui correspondent à vos compositions réelles.
L’essentiel : le comportement du composant doit être testable sans un harnais de page complet.

Débogage en production : ce qui casse et pourquoi

Les modes de défaillance des container queries sont surtout opérationnels : la fonctionnalité est simple,
mais votre DOM ne l’est pas. Les containers se retrouvent entourés, les styles sont refactorisés. Un nouveau composant de layout ajoute
contain ou change le display. Soudain votre composant est « bloqué » en mode compact.

Cause racine la plus courante : aucun query container

Si container-type n’est pas défini (ou est défini sur le mauvais ancêtre), rien ne correspond.
Le CSS se parse correctement. Il n’y a pas d’erreur dans la console. Ça ne fonctionne tout simplement pas.
Voilà pourquoi vous avez besoin d’une routine de diagnostic, pas d’intuitions.

Deuxième cause courante : interroger le mauvais container

Les containers non nommés sélectionnent l’ancêtre le plus proche. Si un wrapper de layout est devenu un container pour une autre raison,
votre composant peut commencer à se baser sur ce wrapper au lieu de celui prévu.
Les noms évitent cela. Utilisez-les.

Troisième cause courante : couplage de styles qui provoque des sauts de layout

Les container queries peuvent provoquer un « flip-flop » si une query change suffisamment la mise en page pour modifier la taille du container,
ce qui modifie le résultat de la query, qui modifie encore la mise en page. Les navigateurs tentent d’éviter les cycles, mais vous pouvez quand même
créer des transitions saccadées ou des reflows inattendus.

Blague #2 : Si votre composant oscille entre deux mises en page, félicitations — vous avez inventé un métronome CSS. Vos utilisateurs n’ont pas demandé du jazz temporel.

Vérification de réalité performance

Les container queries sont implémentées dans les moteurs, donc vous évitez le cauchemar des polyfills JS d’antan.
Mais « natif » ne signifie pas « gratuit ». Si vous établissez des containers partout et attachez beaucoup de
queries fines, vous pouvez créer des coûts mesurables de recalcul de styles lors de redimensionnements et de changements dynamiques de layout.

La solution est ennuyeuse : moins de containers, moins de queries, meilleure composition, et profilage avec des interactions réelles.
C’est la même discipline qu’en backend : mesurer, contraindre et simplifier.

Mode opératoire pour un diagnostic rapide

Quand un composant basé sur container queries se comporte mal, vous voulez trouver le goulot rapidement.
Voici un ordre de triage adapté à la production qui évite les terriers de lapin.

1) Vérifier si un query container existe et lequel est utilisé

  • Inspectez l’élément dans les DevTools.
  • Localisez l’ancêtre le plus proche ayant container-type (ou le raccourci container).
  • S’il y en a plusieurs, confirmez que vous vouliez bien l’ancêtre le plus proche — ou utilisez container-name pour cibler le bon.

2) Vérifier la taille inline réelle du conteneur à l’exécution

  • Toujours dans les DevTools, vérifiez la largeur calculée du conteneur.
  • Comparez-la aux seuils de la query.
  • Si elle est proche d’un seuil et clignote, vous avez probablement une boucle de rétroaction ou un problème d’arrondi.

3) Confirmer que la condition de query correspond à ce que vous pensez

  • Vérifiez si vous utilisez correctement min-width/max-width dans @container.
  • Assurez-vous que vos container queries ciblent le container nommé si vous avez utilisé des noms.
  • Vérifiez si vous avez accidentellement utilisé des unités de container (cqw) en vous attendant à des unités viewport (vw).

4) Chercher des cycles de layout et des effets secondaires du containment

  • Si la query change padding/bordures/scrollbars, elle peut modifier la taille du conteneur.
  • Si vous interrogez la hauteur, soyez particulièrement prudent : le contenu change la hauteur ; la hauteur déclenche la query ; la query change le contenu.
  • Privilégiez les conteneurs inline-size sauf si vous avez vraiment besoin d’interroger la hauteur.

5) Profilage avant « optimisation »

  • Si l’app saccade lors du redimensionnement ou à l’ouverture de panneaux, profilez le recalcul de styles et le layout.
  • Supprimez les containers inutiles et simplifiez les seuils de query.

Erreurs courantes : symptôme → cause → correction

1) Symptom : @container ne s’applique nulle part

Cause : Aucun ancêtre n’a container-type défini, donc aucun query container n’existe.

Correction : Ajoutez container-type: inline-size au wrapper du composant (ou à un wrapper de layout spécifique) et revérifiez les styles calculés.

2) Symptom : Le composant est correct sur une page mais incorrect dans une modale/barre latérale

Cause : Vous avez utilisé des media queries pour un composant qui est embarqué dans différentes largeurs de conteneur.

Correction : Déplacez la logique de breakpoint dans des container queries sur le composant. Conservez les media queries uniquement pour le cadrage de la page.

3) Symptom : Le composant change de mise en page de façon inattendue après un refactor

Cause : Un nouveau wrapper est devenu l’ancêtre le plus proche (sélection de container non nommé), changeant le container interrogé.

Correction : Nommez le container prévu (container-name) et ciblez-le explicitement dans @container.

4) Symptom : La mise en page oscille près d’un breakpoint

Cause : La query change quelque chose qui modifie la largeur du container (scrollbar, padding, colonnes de grille), provoquant des oscillations.

Correction : Ajoutez de l’hystérésis (utilisez des seuils min/max légèrement séparés), évitez les changements affectant la largeur au breakpoint, ou restructurez pour stabiliser la largeur du conteneur.

5) Symptom : La typographie évolue bizarrement dans des composants imbriqués

Cause : Les unités de container sont relatives au query container le plus proche ; l’imbrication change la référence de façon inattendue.

Correction : Utilisez des containers nommés pour les contextes de mise à l’échelle typographique, ou préférez la typographie en rem avec des étapes discrètes de container query.

6) Symptom : Saccades de performance lors du redimensionnement de panneaux ou de l’ouverture de tiroirs

Cause : Trop de containers et trop de seuils de query provoquent des recalculs fréquents de styles/layout pendant les redimensionnements dynamiques.

Correction : Réduisez la portée des containers, regroupez les seuils, et évitez les container queries pour des micro-changements. Mesurez avec des outils de profilage avant/après.

7) Symptom : La query fonctionne dans un navigateur mais pas dans un autre

Cause : Différences de support partiel, anciens webviews intégrés, ou outils de build qui suppriment/réécrivent les at-rules inconnues.

Correction : Ajoutez du progressive enhancement : mise en page de base sans container queries, puis amélioration par layers. Vérifiez que la pipeline CSS préserve @container.

Trois mini-récits d’entreprise tirés du terrain

Mini-récit 1 : L’incident causé par une fausse hypothèse

Une équipe a livré une nouvelle « InsightCard » utilisée dans tout un produit analytique : dashboards, panneaux latéraux, et un rapport en pleine page.
L’implémentation initiale utilisait des media queries. Ça paraissait correct dans le rapport en pleine page, bien sûr.

Puis un client entreprise a construit une mise en page de dashboard personnalisée : une grille à trois colonnes avec une colonne latérale droite réductible.
Quand la colonne s’est étendue, les cartes à l’intérieur s’affichaient toujours en « mode desktop » parce que le breakpoint viewport était satisfait.
Dans une colonne de 320px, la carte essayait d’afficher une grille interne en deux colonnes, des libellés longs et une légende de graphique.
Résultat : débordements, texte coupé, et piège de défilement à l’intérieur d’un conteneur scrollable. Le support l’a qualifié « d’inutilisable ». Ils n’avaient pas tort.

La mauvaise hypothèse était simple : la largeur du viewport approximait la largeur du composant. Ce n’est pas le cas dans les UIs modernes.
Le produit comportait des panneaux partagés, des barres collantes et des modules embarqués. Le viewport était un mensonge, et le mensonge s’est accru avec l’évolution de l’UI.

La correction n’a pas été héroïque. Ils ont défini le wrapper de la carte comme query container nommé et déplacé les breakpoints internes de la carte vers @container.
Les media queries sont restées réservées aux changements de grille au niveau de la page. Une fois livré, la même carte s’est comportée correctement dans la colonne, dans les modales et dans le rapport plein écran.

Mini-récit 2 : L’optimisation qui s’est retournée contre eux

Une autre organisation s’est emballée et a essayé de « standardiser la responsivité » en faisant de chaque wrapper de layout un query container.
En-têtes, sections, cellules de grille, panneaux — tout avait container-type: inline-size.
C’était vendu comme une préparation au futur. C’était aussi une excellente manière de rendre le débogage impossible.

Le premier problème visible était étrange : les composants ont commencé à réagir à différents containers selon leur lieu de rendu.
Un composant qui s’attendait à interroger son propre wrapper interrogeait désormais un wrapper externe parce que le DOM avait changé.
Le second problème, moins visible mais plus coûteux : les coûts de recalcul des styles ont monté lors des interactions de drag-resize.
L’UI ne « plantait » pas, elle semblait collante, comme traîner dans de la boue.

L’« optimisation » de l’équipe a créé un énorme graphe de dépendances implicite. Trop de containers signifiait trop de contextes de query potentiels.
Et comme beaucoup étaient redondants, le navigateur effectuait du travail supplémentaire pour les maintenir. Rien n’alarmait les tableaux de bord de performance.
Les utilisateurs ont simplement cessé de faire confiance à l’UI.

La stratégie de rollback fut instructive : ils ont retiré container-type des wrappers génériques et l’ont gardé seulement sur les racines de composants qui en avaient réellement besoin.
Ils ont nommé les containers clés. Le débogage est redevenu sensé, les performances se sont améliorées, et le système est redevenu explicable — ce que l’on veut en production.

Mini-récit 3 : La pratique ennuyeuse mais correcte qui a sauvé la mise

Une équipe plateforme maintenait une bibliothèque de composants utilisée par plusieurs squads produit.
Ils ont introduit les container queries prudemment : chaque composant avait une mise en page de base sans container queries,
puis les container queries étaient ajoutées comme amélioration progressive. Ils ont aussi écrit une petite guideline interne :
« Les breakpoints de composant doivent être documentés comme états de composant, et les containers doivent être nommés. »

Des mois plus tard, une squad a embarqué la bibliothèque dans un environnement hôte tiers avec un webview ancien.
Les container queries ne s’appliquaient pas. La squad s’attendait à un désastre, car les fonctionnalités CSS modernes échouent souvent bruyamment dans les contextes legacy.
Au lieu de ça, l’UI est restée utilisable : la mise en page de base était simple, flexible et n’était pas dépendante du support des queries.

La réponse à l’incident fut ennuyeuse dans le meilleur sens. Ils ont détecté le manque de support en QA,
accepté l’expérience de base pour cet hôte, et évité de livrer un polyfill fragile.
Le produit a continué de fonctionner. La release est restée dans les temps. Personne n’a passé une nuit blanche pour lutter contre du CSS.

C’est le genre de « succès d’ingénierie » qui ne devient jamais une légende parce qu’il ne crée pas de drame.
Il empêche simplement le drame.

Tâches pratiques avec commandes (et décisions)

Les container queries sont du CSS, mais les livrer est un travail opérationnel : pipelines de build, support des navigateurs,
tests de régression et profilage de performance. Voici de vraies tâches que vous pouvez lancer dans un repo typique.
Chaque tâche inclut une commande, un exemple de sortie, ce que cela signifie, et la décision à prendre.

Tâche 1 : Vérifier les targets browserslist (pour savoir ce que vous promettez)

cr0x@server:~$ cat package.json | sed -n '1,120p'
{
  "name": "ui-app",
  "version": "1.0.0",
  "browserslist": [
    "last 2 chrome versions",
    "last 2 firefox versions",
    "last 2 safari versions",
    "not dead"
  ]
}

Ce que la sortie signifie : Votre transpilation et vos outils CSS cibleront ces navigateurs.

Décision : Si vous devez supporter d’anciens webviews embarqués, prévoyez des mises en page de base et évitez de dépendre des container queries pour l’essentiel de l’UX.

Tâche 2 : Confirmer que votre build CSS ne supprime pas les règles @container

cr0x@server:~$ rg -n "@container" src/styles
src/styles/card.css:11:@container card (min-width: 520px) {
src/styles/widgets.css:21:@container widget (max-width: 479px) {

Ce que la sortie signifie : Votre source contient des container queries comme prévu.

Décision : Si la sortie build ne les contient pas, inspectez la configuration PostCSS/minifier et assurez-vous qu’elle préserve correctement les at-rules inconnues.

Tâche 3 : Inspecter le CSS compilé pour la présence des container queries

cr0x@server:~$ ls -lh dist/assets/app.css
-rw-r--r-- 1 cr0x cr0x 412K Sep  4 11:20 dist/assets/app.css
cr0x@server:~$ rg -n "@container" dist/assets/app.css | head
1842:@container card (min-width: 520px){.card{grid-template-columns:220px 1fr}}
1901:@container widget (max-width: 479px){.widget .meta{display:none}}

Ce que la sortie signifie : Les règles de container query survivent à votre pipeline.

Décision : Si elles ne sont pas présentes, corrigez le build avant de déboguer le layout ; autrement vous déboguez du code qui n’est jamais livré.

Tâche 4 : Valider que votre CSS est syntaxiquement correct (lint rapide)

cr0x@server:~$ npx stylelint "src/**/*.css"
src/styles/card.css
  11:1  warning  Unexpected unknown at-rule "@container"  at-rule-no-unknown

Ce que la sortie signifie : Votre linter ne reconnaît pas les container queries (ou n’est pas configuré pour elles).

Décision : Mettez à jour la configuration stylelint pour autoriser @container. Sinon les devs risquent de « corriger » votre fonctionnalité en la supprimant.

Tâche 5 : Vérifier la configuration stylelint pour la gestion des at-rules

cr0x@server:~$ cat .stylelintrc.json
{
  "rules": {
    "at-rule-no-unknown": [true, {
      "ignoreAtRules": ["container", "layer"]
    }]
  }
}

Ce que la sortie signifie : Le lint ne signalera plus la syntaxe valide des container queries.

Décision : Appliquez cela dans les repos avant de déployer largement les container queries.

Tâche 6 : Suivre où vous définissez container-type (éviter le « container partout »)

cr0x@server:~$ rg -n "container-type:" src | head -n 20
src/styles/card.css:2:  container-type: inline-size;
src/styles/widget.css:3:  container-type: inline-size;
src/styles/layout.css:5:  container-type: inline-size;

Ce que la sortie signifie : Vous voyez quels fichiers introduisent des query containers.

Décision : Si des wrappers génériques sont containers par défaut, reconsidérez. Rendez les containers intentionnels et nommés.

Tâche 7 : Détecter les containers non nommés (plus difficiles à déboguer)

cr0x@server:~$ rg -n "container-name:" src/styles | wc -l
2

Ce que la sortie signifie : Vous avez peu de containers nommés par rapport à l’utilisation des containers.

Décision : Ajoutez des noms pour les containers qui font partie d’un contrat de composant ou qui apparaissent dans plusieurs contextes d’imbrication.

Tâche 8 : Trouver les seuils de container queries dans le code (standardisez-les)

cr0x@server:~$ rg -n "@container .*min-width" src/styles | head -n 20
src/styles/card.css:11:@container card (min-width: 520px) {
src/styles/widget.css:10:@container widget (min-width: 480px) {
src/styles/table.css:27:@container results (min-width: 640px) {

Ce que la sortie signifie : Des breakpoints existent par composant.

Décision : Si les valeurs sont arbitraires, créez des guidelines d’état de composant (compact/regular/spacious) et alignez les seuils quand c’est pertinent.

Tâche 9 : Confirmer que la mise en page de base fonctionne sans container queries (style feature-flag)

cr0x@server:~$ rg -n "@container" src/styles/card.css
11:@container card (min-width: 520px) {
cr0x@server:~$ sed -n '1,40p' src/styles/card.css
.card {
  container-type: inline-size;
  container-name: card;
  display: grid;
  gap: 12px;
}

Ce que la sortie signifie : Le .card de base est déjà une mise en page raisonnable sans la règle de query.

Décision : Gardez la mise en page de base utilisable ; traitez les container queries comme une amélioration, pas comme une condition nécessaire à la lisibilité.

Tâche 10 : Utiliser Playwright pour rendre un composant à des largeurs de conteneur contrôlées

cr0x@server:~$ cat tests/card-container-width.spec.js
const { test, expect } = require('@playwright/test');

test('card switches layout at container width', async ({ page }) => {
  await page.setContent(`
    
    
media
body
`); const card = page.locator('.card'); await expect(card).toHaveCSS('grid-template-columns', 'none'); });
cr0x@server:~$ npx playwright test tests/card-container-width.spec.js
Running 1 test using 1 worker

  ✓  1 tests/card-container-width.spec.js:3:1 › card switches layout at container width (1.2s)

  1 passed (2.0s)

Ce que la sortie signifie : Vous pouvez tester le layout piloté par container de manière déterministe.

Décision : Ajoutez des tests pour les frontières d’état clés afin que de futurs changements DOM n’altèrent pas silencieusement le container interrogé.

Tâche 11 : Auditer le bundle pour des règles de container query dupliquées (gourmandise CSS)

cr0x@server:~$ rg -n "@container card" dist/assets/app.css | wc -l
18

Ce que la sortie signifie : Il y a de nombreux blocs de container query pour card — possiblement des doublons provenant de variantes de composants.

Décision : Consolidez les règles partagées de container query, ou refactorez les variantes pour qu’elles se composent plutôt que de dupliquer.

Tâche 12 : Vérifier l’utilisation accidentelle d’unités de container alors que des unités viewport étaient attendues

cr0x@server:~$ rg -n "\bcq(w|h|i|b|min|max)\b" src/styles | head -n 30
src/styles/hero.css:14:  font-size: clamp(1.2rem, 2.2cqw, 2.0rem);
src/styles/badge.css:8:  padding: 0.6cqi 1.2cqi;

Ce que la sortie signifie : Des unités de container sont utilisées en typographie/espacements.

Décision : Confirmez que chaque usage a le bon contexte de container et ne s’agrandira pas de façon inattendue lorsqu’il est imbriqué. Si doute, préférez rem + étapes discrètes de container query.

Tâche 13 : Confirmer que personne n’a « aidé » en ajoutant container-type aux wrappers globaux

cr0x@server:~$ rg -n "container-type: inline-size" src/styles/layout.css
5:.layout-shell { container-type: inline-size; }

Ce que la sortie signifie : Un wrapper de haut niveau est un query container pour tout ce qu’il contient.

Décision : À moins d’avoir une raison documentée, supprimez-le. Les containers globaux créent des couplages implicites et une sélection de query déroutante.

Tâche 14 : Créer un rapport léger de « contrat de container » pour la revue PR

cr0x@server:~$ rg -n "container-(type|name):" src/styles | sort
src/styles/card.css:2:  container-type: inline-size;
src/styles/card.css:3:  container-name: card;
src/styles/table.css:4:  container-type: inline-size;
src/styles/table.css:5:  container-name: results;
src/styles/widget.css:3:  container-type: inline-size;
src/styles/widget.css:4:  container-name: widget;

Ce que la sortie signifie : Un inventaire concis des définitions de containers.

Décision : Exigez des noms de container pour les composants partagés. Faites demander aux reviewers : « Est-ce le bon container, et est-il stable face aux refactors ? »

Tâche 15 : Vérification rapide que votre minifier CSS ne réécrit pas incorrectement les container queries

cr0x@server:~$ node -p "require('fs').readFileSync('dist/assets/app.css','utf8').includes('@container')"
true

Ce que la sortie signifie : Un contrôle booléen basique que la sortie contient l’at-rule.

Décision : Si c’est faux, arrêtez-vous. Corrigez la pipeline. Ne livrez pas une fonctionnalité que votre build supprime.

Listes de contrôle / plan pas à pas

Plan pas à pas pour adopter les container queries dans un vrai codebase

  1. Choisir un composant à fort impact (card, toolbar, résumé de données, tuile tarifaire).
    Prenez quelque chose réutilisé dans plusieurs mises en page et qui a actuellement des bugs de breakpoint.
  2. Définir le conteneur du composant (généralement la racine du composant).
    Ajoutez container-type: inline-size et container-name.
  3. Écrire d’abord une mise en page de base qui fonctionne sans container queries.
    Rendez-la lisible, pas parfaite.
  4. Ajouter 1–3 seuils de container query mappés aux états du composant.
    Gardez les transitions significatives (pile → colonnes, cacher → montrer, compact → aéré).
  5. Interdire les containers non nommés dans les composants partagés.
    Les noms évitent les changements de comportement accidentels quand des wrappers sont introduits.
  6. Ajouter des tests de largeur composant (visuels ou assertions CSS).
    Testez aux largeurs autour de vos seuils.
  7. Inventorier les containers au fur et à mesure de l’adoption.
    Trop de containers est un risque de maintenabilité et de performance.
  8. Déployer progressivement.
    Surveillez les patterns de régression : layouts imbriqués, modales, rails latéraux et contextes embarqués.
  9. Profiler les interactions dynamiques (drag resize, ouverture/fermeture de tiroir, scroll infini).
    Si les performances régressent, réduisez la granularité des queries et la portée des containers.
  10. Documenter le contrat pour chaque composant :
    quel élément est le container, quels sont les états, et quelles largeurs les déclenchent.

Checklist opérationnelle pour la revue PR

  • Le composant a-t-il un query container nommé ?
  • Les breakpoints sont-ils exprimés comme états de composant, et non comme labels d’appareil ?
  • La mise en page de base est-elle acceptable lorsque les container queries ne s’appliquent pas ?
  • Les seuils de query sont-ils stables (pas d’oscillation aux frontières) ?
  • Le changement ajoute-t-il container-type à un wrapper générique ? Si oui, pourquoi ?
  • Les unités de container sont-elles utilisées intentionnellement, avec un contexte de container connu ?
  • Y a-t-il au moins un test qui couvre les frontières d’état ?

FAQ

1) Les container queries doivent-elles remplacer totalement les media queries ?

Non. Utilisez les media queries pour les décisions au niveau page liées au viewport (navigation globale, grille globale).
Utilisez les container queries pour l’intérieur des composants. Les mélanger sans plan conduit au whiplash des breakpoints.

2) Quel est le minimum nécessaire pour faire fonctionner @container ?

Un élément ancêtre avec container-type défini, typiquement inline-size.
Sans cela, il n’y a pas de query container et vos règles ne correspondront pas.

3) Pourquoi mes container queries fonctionnent-elles à un endroit mais pas à un autre ?

Vous interrogez probablement un container différent de celui que vous pensez (sélection par l’ancêtre le plus proche).
Nommez vos containers et ciblez-les explicitement pour éviter les changements accidentels quand des wrappers sont introduits.

4) Les container queries sont-elles sûres pour les performances ?

Généralement oui si vous les utilisez avec intention, mais elles ne sont pas gratuites.
Trop de containers et trop de seuils peuvent augmenter le travail de style/layout lors de redimensionnements dynamiques et de transitions UI.
Profilez les interactions importantes et gardez les queries grossières.

5) Dois-je utiliser container-type: size ?

Seulement si vous avez vraiment besoin d’interroger largeur et hauteur. La plupart des composants devraient n’interroger que la largeur.
Les requêtes sur la hauteur créent plus facilement des boucles de rétroaction et des comportements saccadés parce que le contenu pilote souvent la hauteur.

6) En quoi les unités de container query (cqw, cqh) diffèrent-elles de vw/vh ?

Les unités de container sont relatives au query container, pas au viewport.
C’est excellent pour l’échelle locale, mais déroutant dans des contextes imbriqués. Utilisez-les pour des ajustements mineurs ; gardez la typographie centrale stable.

7) Quelle est la meilleure façon de tester le comportement des container queries ?

Rendre le composant à des largeurs de conteneur contrôlées dans des tests automatisés.
Ne vous fiez pas uniquement aux captures d’écran de pages entières. Les tests à la largeur du composant attrapent les régressions d’intégration.

8) Comment gérer les navigateurs plus anciens ou les webviews embarqués ?

Progressive enhancement. La mise en page de base fonctionne sans container queries ; les container queries l’améliorent quand elles sont supportées.
Évitez les polyfills fragiles sauf si vous n’avez aucune alternative et que vous pouvez gérer la complexité opérationnellement.

9) Puis-je imbriquer des container queries ?

Oui, mais vous devez être explicite sur le container que vous interrogez.
Utilisez container-name pour éviter les surprises. L’imbrication sans noms est ce qui transforme le comportement responsive en folklore.

10) Quel est le plus gros « piège » rencontré par les équipes ?

Traiter les container queries comme une solution magique qui remplace la réflexion sur le layout.
Si votre composant est structurellement fragile, les container queries feront juste échouer ce composant dans plus d’endroits, et de manière plus créative.

Conclusion : prochaines étapes à livrer

Les container queries sont la bonne abstraction pour la composition UI moderne : des composants qui répondent à l’espace qui leur est donné,
pas à l’écran que vous tenez. Bien utilisées, elles éliminent toute une catégorie de bugs responsive.
Mal utilisées, elles en créent de nouveaux, plus difficiles à repérer et plus faciles à déclencher.

Prochaines étapes pratiques :

  • Choisissez un composant à fort impact et déplacez sa responsivité interne des media queries vers un container nommé.
  • Gardez la mise en page de base utilisable sans container queries. C’est votre histoire de compatibilité et de résilience.
  • Standardisez les états de composant et les seuils, et écrivez des tests aux largeurs de conteneur autour des frontières.
  • Auditez et réduisez les containers « ambiants » dans les wrappers de layout. Les containers doivent être intentionnels, pas contagieux.
  • Utilisez le mode opératoire de diagnostic rapide quand quelque chose casse ; ne devinez pas quel ancêtre est le container.

L’objectif n’est pas d’utiliser la dernière fonctionnalité CSS partout. L’objectif est d’arrêter de livrer des UI qui ne fonctionnent que dans la seule mise en page que vous avez testée.
Les container queries, employées avec retenue, vous y amènent.

← Précédent
Proxmox ralenti après une mise à jour : les premières vérifications qui révèlent généralement la cause
Suivant →
Proxmox : SMB/CIFS lent pour les disques VM — pourquoi c’est mauvais et quoi utiliser à la place

Laisser un commentaire