Mise en page responsive avec Tailwind : container queries et stratégie de breakpoints

Chapeau
Vous fixez l’écran : ce composant carte.
Sur la page d’accueil, tout est parfait — image à gauche, texte à droite, espacements confortables. Copié dans la barre latérale, la mise en page s’effondre comme un papier froissé. L’image se compresse, le texte se casse n’importe comment.
Comment ce truc est-il censé savoir à quoi il doit ressembler ?
Le responsive classique ne regarde que le viewport — la fenêtre du navigateur. Le composant ignore la largeur du conteneur qui l’accueille. Comme quelqu’un habitué à une villa, jeté dans un studio de trente mètres carrés sans savoir où placer les meubles.
Les container queries Tailwind comblent ce trou : le composant perçoit la taille de son conteneur au lieu de ne regarder que la fenêtre.
Cet article couvre les deux pièges les plus fréquents du responsive Tailwind : choisir sa stratégie de breakpoints et utiliser les container queries. Beaucoup de code concret — cent lectures de doc ne valent pas un essai sur votre layout.
L’évolution du responsive : du viewport au conteneur
Media queries : les limites de l’ancienne méthode
Les media queries, on les utilise depuis des années ; elles semblent suffisantes — jusqu’au jour où la même carte doit aller dans trois contextes : flux d’accueil, encart latéral, liste dans une modale.
Le problème apparaît.
La media query mesure le viewport, pas ce qui compte pour le composant : la largeur du parent.
Exemple :
/* Media query classique */
@media (min-width: 768px) {
.card {
flex-direction: row;
}
}
Signification : si la fenêtre dépasse 768px, la carte passe en horizontal.
Mais si le viewport fait 1200px et la barre latérale seulement 280px ? La carte reste horizontale et se tasse dans ce couloir étroit.
On a l’impression de chausser du 44 dans du 38.
Container queries : changer de question
La container query ne demande pas « quelle est la fenêtre ? » mais « quelle est mon boîte ? ».
/* Container query */
@container (min-width: 400px) {
.card {
flex-direction: row;
}
}
Ici : quand le conteneur dépasse 400px, la carte passe en horizontal.
« Et alors ? » — la différence est énorme.
Même carte : zone de contenu à 600px → horizontal sans souci ; barre latérale à 280px → empilement vertical automatique. Pas de double composant, pas de props, pas de rafales de conditions.
Le composant devient enfin réutilisable.
Support navigateur
Vers 2023, les navigateurs majeurs ont généralisé les container queries. En 2024, le support des Container Size Queries dépasse 90 % — Chrome, Firefox, Safari, Edge.
Projets legacy : peut-être attendre encore un peu. Pour la plupart des sites actuels, c’est jouable.
Le système de breakpoints Tailwind CSS
Avant les container queries, clarifions les breakpoints Tailwind — c’est la base.
Les breakpoints par défaut
Cinq seuils par défaut :
| Préfixe | Largeur min. | Scénario typique |
|---|---|---|
sm: | 640px | Grand téléphone paysage |
md: | 768px | Tablette portrait |
lg: | 1024px | Tablette paysage / petit portable |
xl: | 1280px | Écran bureau |
2xl: | 1536px | Grand écran |
Pas besoin de tout mémoriser : l’essentiel est que Tailwind est mobile-first — md:flex-row signifie « à partir de 768px de viewport, appliquer flex-row ».
Mobile-first : d’abord le petit écran
Par défaut, vous stylez le mobile, puis vous enrichissez avec les breakpoints.
<!-- Mobile-first -->
<div class="flex flex-col md:flex-row lg:gap-8">
<!-- mobile : empilement vertical -->
<!-- tablette (md) : horizontal -->
<!-- bureau (lg) : espacement plus large -->
</div>
Styles simples d’abord, puis couches — utile pour les appareils modestes.
Le « desktop-first » impose des breakpoints inverses ; sauf contrainte projet, le mobile-first reste plus simple.
Quand personnaliser les breakpoints
La plupart du temps, les valeurs par défaut suffisent. Exceptions : design system avec des seuils custom.
Exemple : back-office avec 480px, 720px, 960px, 1200px — il faut toucher tailwind.config.js :
// tailwind.config.js
module.exports = {
theme: {
screens: {
'xs': '480px', // breakpoint plus petit
'sm': '640px',
'md': '720px', // remplace la valeur par défaut
'lg': '960px',
'xl': '1200px',
}
}
}
Besoin d’un seuil sous sm pour très petits écrans :
screens: {
'xs': '475px', // nouveau
'sm': '640px',
// ... reste inchangé
}
Nommer les breakpoints
Piège personnel : nommer mobile, tablet, desktop. Pliants, écrans embarqués — les noms vieillissent mal.
Désormais : sm, md, lg — tailles, pas appareils. Les noms restent valables quand de nouveaux formats arrivent.
Container queries en pratique : faire « sentir » l’espace au composant
Cette section montre du code concret.
Étape 1 : déclarer le conteneur
Il faut dire au navigateur : cet élément est un conteneur de requête.
En Tailwind, une classe @container :
<!-- Parent -->
<div class="@container">
<!-- Les enfants s'adaptent à la taille du conteneur -->
<div class="flex flex-col @sm:flex-row">
...
</div>
</div>
Ce div devient conteneur ; les enfants utilisent @sm, @md, etc.
Les breakpoints conteneur
Ils diffèrent des breakpoints viewport :
| Breakpoint | Largeur min. |
|---|---|
@xs | 320px |
@sm | 384px |
@md | 448px |
@lg | 512px |
@xl | 576px |
@2xl | 672px |
@3xl | 768px |
@4xl | 896px |
@5xl | 1024px |
Plus petits que sm/md viewport — logique : le conteneur est imbriqué, il ne peut pas être plus large que la fenêtre.
Cas 1 : carte adaptive
Carte utilisable partout :
- conteneur < 384px : vertical, image pleine largeur
- conteneur >= 384px : horizontal, largeur d’image fixe
- conteneur >= 512px : image plus grande, plus de lignes de texte
<!-- Parent : conteneur de requête -->
<div class="@container p-4">
<article class="flex flex-col @sm:flex-row @lg:gap-6 bg-white rounded-lg shadow">
<img
src="https://example.com/image.jpg"
alt="Illustration d'article"
class="w-full @sm:w-32 @lg:w-48 h-48 @sm:h-32 @lg:h-36 object-cover rounded-t-lg @sm:rounded-l-lg @sm:rounded-tr-none"
/>
<div class="p-4 @sm:py-2 @lg:py-4 flex-1">
<h3 class="text-base @lg:text-lg font-semibold mb-2">
Guide d'introduction aux container queries Tailwind
</h3>
<p class="text-sm text-gray-600 line-clamp-2 @lg:line-clamp-3">
Comment utiliser les container queries Tailwind CSS pour un vrai responsive au niveau composant...
</p>
<div class="mt-3 flex items-center text-xs text-gray-400">
<span>2026-03-27</span>
<span class="mx-2">·</span>
<span>5 min de lecture</span>
</div>
</div>
</article>
</div>
Barre latérale 280px : layout vertical compact. Zone 600px : horizontal aéré. Même markup.
Cas 2 : barre de navigation réutilisable
La navigation illustre bien l’intérêt : même composant en en-tête large, barre latérale étroite, tiroir mobile.
<nav class="@container">
<ul class="flex flex-col @lg:flex-row @lg:items-center gap-2 @lg:gap-6">
<li>
<a href="/" class="block py-2 px-3 rounded hover:bg-gray-100">
Accueil
</a>
</li>
<li>
<a href="/posts" class="block py-2 px-3 rounded hover:bg-gray-100">
Articles
</a>
</li>
<li>
<a href="/about" class="block py-2 px-3 rounded hover:bg-gray-100">
À propos
</a>
</li>
</ul>
</nav>
À partir de 512px de conteneur (@lg), les liens passent en ligne.
Un seul composant, plusieurs emplacements, sans variantes CSS par contexte.
Limites des container queries
1. Pas de requête sur la hauteur
Seule la largeur est supportée aujourd’hui.
/* N'a pas d'effet */
@container (min-height: 400px) {
/* pas encore supporté */
}
2. Conteneur de taille requis
@container crée un conteneur de taille ; seuls ses descendants interrogent ce conteneur (ou un ancêtre conteneur plus proche, pas forcément le parent direct).
3. Peu d’imbrication
Trop de niveaux @container coûte en perf. Deux à trois niveaux max, puis refactor.
Choisir sa stratégie : media query vs container query
Critère simple : de quoi dépend le style ?
Arbre de décision
De quoi ce style dépend-il ?
├─ Viewport → media queries (md:, lg:, …)
│ ├─ Grille de page
│ ├─ Navigation globale, header, footer
│ ├─ Hero, bannières plein écran
│ └─ Éléments ancrés au viewport
│
└─ Conteneur → container queries (@sm:, @lg:, …)
├─ Composants réutilisables (cartes, lignes)
├─ Widgets de barre latérale
├─ Contenu de modale
└─ Composants imbriqués
Scénarios media query
Mise en page de page : colonnes selon la fenêtre.
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<!-- cartes -->
</div>
Navigation globale : menu burger vs barre horizontale selon viewport.
<header class="flex items-center justify-between px-4 py-3">
<div class="logo">Logo</div>
<nav class="hidden md:flex gap-6">
<a href="/">Accueil</a>
<a href="/posts">Articles</a>
<a href="/about">À propos</a>
</nav>
<button class="md:hidden">
<span class="sr-only">Ouvrir le menu</span>
<!-- icône hamburger -->
</button>
</header>
Scénarios container query
Composants réutilisables : carte en flux d’accueil (~300–400px), recommandations (~250px), barre latérale (~280px).
Imbrication :
<div class="@container w-full md:w-80">
<div class="@container">
<div class="@sm:flex-row @lg:gap-4">
...
</div>
</div>
</div>
Combinaison
Page en media query, composants en container query :
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
<main class="md:col-span-2">
<div class="@container">
<article class="flex flex-col @sm:flex-row">
<!-- contenu carte -->
</article>
</div>
</main>
<aside class="@container">
<div class="@sm:grid-cols-2">
<!-- widgets -->
</div>
</aside>
</div>
Structure globale selon l’appareil ; détail interne selon l’espace réel — deux couches, deux rôles.
Performance et bonnes pratiques
Coût des container queries
Le navigateur calcule et observe les tailles de conteneur — coût faible sauf abus d’imbrication.
Erreur vue en prod : @container sur chaque item de liste, puis encore plusieurs niveaux — léger lag au scroll.
<!-- À éviter : @container à chaque niveau -->
<div class="@container">
<div class="@container">
<div class="@container">
<div class="@sm:flex-row">
</div>
</div>
</div>
</div>
<!-- Mieux : un seul @container utile -->
<div class="@container">
<div>
<div>
<div class="@sm:flex-row">
</div>
</div>
</div>
</div>
Ne pas sur-utiliser
Hero fixe en page d’accueil : media query suffit ; @container serait du bruit.
Règle : container query seulement si le composant vit dans des conteneurs de largeurs variées. Sinon, media query.
Débogage
DevTools → Elements → élément @container → Styles → règles @container → survol des breakpoints pour surligner le conteneur.
Computed → recherche container-type pour vérifier le statut.
Checklist
- Imbrication : 2–3
@containermax - Usage : réutilisation multi-contexte ; sinon media query
- Noms :
sm/md/lg, pasmobile/tablet - Sélecteurs : rester simples dans les blocs conteneur
- Animations : éviter de lier des animations à des changements fréquents de taille de conteneur
Testez dans des conteneurs étroits et larges — beaucoup de bugs n’apparaissent qu’après mise en prod.
Synthèse
Problème résolu : le composant s’adapte à son conteneur, pas seulement au viewport — vraie réutilisation.
Principe :
- page → media queries (
md:,lg:) - composants → container queries (
@sm:,@lg:)
Perf : peu d’imbrication, pas d’usage systématique.
Un composant à réutiliser ? Commencez par une carte. Vous éviterez souvent de dupliquer des variantes par emplacement.
Pour aller plus loin : Container Queries (Tailwind) et CSS Container Queries (MDN).
Des questions ? La section commentaires est ouverte.
Composants responsive avec les container queries Tailwind
De zéro aux container queries Tailwind CSS pour adapter la mise en page au conteneur
⏱️ Estimated time: 30 min
- 1
Step 1: Ajouter @container sur le parent
Repérez le conteneur parent du composant à rendre responsive et ajoutez la classe `@container` :
```html
<div class="@container">
<!-- Les enfants peuvent utiliser les breakpoints conteneur -->
</div>
```
Cela indique au navigateur que cet élément est un conteneur de requête. - 2
Step 2: Appliquer les breakpoints conteneur sur les enfants
Les enfants peuvent utiliser `@sm:`, `@md:`, `@lg:` et autres :
```html
<div class="@container">
<article class="flex flex-col @sm:flex-row @lg:gap-6">
<!-- conteneur < 384px : disposition verticale -->
<!-- conteneur >= 384px : disposition horizontale -->
<!-- conteneur >= 512px : espacement accru -->
</article>
</div>
```
Valeurs : @xs (320px), @sm (384px), @md (448px), @lg (512px), @xl (576px), etc. - 3
Step 3: Ajuster images et typographie
Adaptez taille d'image et styles de texte à la largeur du conteneur :
```html
<img class="w-full @sm:w-32 @lg:w-48 h-48 @sm:h-32 object-cover" />
<p class="text-sm @lg:text-base line-clamp-2 @lg:line-clamp-3">
```
Image pleine largeur dans un petit conteneur, 128px en moyen, 192px en grand. - 4
Step 4: Combiner media queries et container queries
Mise en page de page en media query, composants en container query :
```html
<!-- Page : media queries -->
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
<main class="md:col-span-2">
<!-- Composant : container queries -->
<div class="@container">
<article class="flex flex-col @sm:flex-row">...</article>
</div>
</main>
<aside class="@container">...</aside>
</div>
```
Chacun son rôle, sans mélanger les responsabilités. - 5
Step 5: Performance et débogage
Points d'attention :
• Imbriquez au plus 2-3 niveaux de `@container` pour limiter l'impact perf
• Réservez les container queries aux composants réutilisables ; scènes fixes → media queries
• Chrome DevTools : Elements → sélectionner le conteneur → panneau Styles, règles @container
• Panneau Computed, recherche `container-type` pour confirmer le statut de conteneur
FAQ
Quelle différence entre container queries et media queries ?
Quel support navigateur pour les container queries Tailwind ?
Container query ou media query : quand choisir ?
• Media queries : mise en page globale, navigation, zone Hero, éléments liés au viewport
• Container queries : composants réutilisables (cartes, lignes de liste), widgets de barre latérale, contenu de modale, composants imbriqués
En pratique, on combine souvent les deux : page en media query, composants en container query.
Les breakpoints conteneur Tailwind ont-ils les mêmes valeurs que les breakpoints viewport ?
Les container queries posent-elles un problème de performance ?
Peut-on interroger la hauteur en container query ?
Comment déboguer les container queries dans Chrome DevTools ?
Alternative : panneau Computed, recherche `container-type` pour confirmer le conteneur de requête.
9 min de lecture · Publié le: 27 mars 2026 · Mis à jour le: 27 juil. 2026
Tailwind & shadcn/ui en pratique
Si vous arrivez depuis la recherche, le plus rapide est de passer à l’article précédent ou suivant de cette série.
Précédent
Construire un squelette admin avec shadcn/ui : Sidebar + Layout, bonnes pratiques
Maîtrisez les bonnes pratiques d'intégration shadcn/ui Sidebar et Next.js Layout. De l'architecture des composants au design responsive et au contrôle d'accès — un squelette admin extensible pas à pas, avec exemples de code complets
Partie 5 sur 14
Suivant
Mode sombre Tailwind : class vs data-theme, deux approches comparées
Comparaison systématique des modes sombre Tailwind CSS via class et data-theme : principes, configuration et intégration framework pour choisir la bonne approche.
Partie 7 sur 14



Commentaires
Connectez-vous avec GitHub pour laisser un commentaire