Optimisation des performances Tailwind : JIT, configuration content et contrôle du volume en production

Ouvrez Chrome DevTools et regardez ce fichier CSS de 3,5 Mo.
Une page de nouvelle fonctionnalité vient d’être mise en ligne ; le temps de chargement est passé de 800 ms à 3,2 secondes. Après un tour de diagnostic, le problème venait bien de ce fichier CSS — rempli de classes Tailwind jamais utilisées.
Tailwind se vend comme « performant », comment peut-il ralentir le site ?
Finalement, le problème n’était pas Tailwind, mais la configuration. Une fois le fonctionnement du mode JIT compris, la config content ajustée, et quelques optimisations de build production appliquées, le CSS passe du Mo au Ko — le site de Netflix n’utilise plus que 6,5 Ko.
Aujourd’hui, je partage les pièges que j’ai rencontrés.
I. Mode JIT : la révolution performance de Tailwind
1.1 Les limites du mode traditionnel
Avant de voir ce fichier CSS de 3,5 Mo, je voyais Tailwind surtout comme un « framework CSS utility-first ».
Le « mode traditionnel » d’avant Tailwind v2 pré-générait toutes les combinaisons de classes possibles — toutes les couleurs, tous les espacements, toutes les variantes (hover, focus, disabled, etc.). Sur un projet moyennement complexe, le CSS de développement pouvait dépasser 10 Mo.
En local, 10 Mo de CSS ne choquent pas — la bande passante n’est pas le problème. Mais le navigateur doit parser une feuille aussi lourde ; la mémoire et les perfs DevTools en souffrent.
En déboguant dans Firefox, j’ai déjà eu des freezes de plusieurs secondes après un changement de classe ; le rechargement de page devenait pénible.
Pire encore : en mode traditionnel, on hésite à toucher la config. Nouveau breakpoint ou variante focus-visible ? Il faut d’abord estimer « combien de combinaisons en plus ». L’équipe finit par choisir entre performance et flexibilité.
1.2 Comment fonctionne le JIT
Le mode JIT (Just-in-Time), introduit en Tailwind v2.1 et activé par défaut en v3+, repose sur une idée simple : génération à la demande.
Le mode traditionnel pré-génère toutes les combinaisons possibles, même inutilisées. Le JIT fait l’inverse — il scanne vos templates (HTML, JSX, Vue, etc.), repère les classes réellement utilisées, puis ne génère que ces styles.
Exemple concret. En mode traditionnel, Tailwind produit du CSS comme :
.bg-black { background-color: #000 }
.hover\:bg-black:hover { background-color: #000 }
.focus\:bg-black:focus { background-color: #000 }
.disabled\:bg-black:disabled { background-color: #000 }
/* ... des dizaines d'autres combinaisons de variantes */
Même si le projet n’utilise qu’un seul bg-black, toutes les autres variantes sont générées.
Avec le JIT, c’est différent. Il scanne les templates, voit seulement bg-black et hover:bg-black, et ne génère que :
.bg-black { background-color: #000 }
.hover\:bg-black:hover { background-color: #000 }
Résultat : le CSS de développement passe de 10 Mo à quelques Ko — le même ordre de grandeur qu’en production.
1.3 Gains concrets du JIT
Je me souviens de ma première activation du JIT : le rechargement était si rapide que ça semblait irréel — plusieurs secondes avant, quasi instantané après.
Vitesse de build : un build complet prenait 2-3 minutes ; maintenant quelques secondes. Le JIT n’a plus besoin de pré-générer tous les styles, il suffit de scanner les templates et d’extraire les classes.
Expérience de développement : DevTools ne freeze plus. Avant, changer une classe forçait le navigateur à reparser 10 Mo de styles ; avec quelques Ko, la mise à jour est quasi immédiate.
Valeurs arbitraires : bonus inattendu. En mode traditionnel, pour text-[#facc15], il fallait souvent une safelist. Le JIT l’accepte directement :
// Pas besoin de pré-définir dans la config, utilisez directement
<h1 class="text-[2.5rem] mt-[1.35rem] text-[#facc15]">
Le JIT simplifie tout
</h1>
Classes dynamiques : en mode traditionnel, 'text-' + color n’est pas détecté. Le JIT a aussi ses limites, mais avec safelist on gère mieux les cas dynamiques.
Vous vous demandez peut-être comment activer le JIT. Aujourd’hui (Tailwind v3+), c’est le défaut, sans config supplémentaire. Sur v2 :
// tailwind.config.js
module.exports = {
mode: 'jit', // v2 : activation manuelle
content: ['./src/**/*.{html,js,jsx,ts,tsx}'],
// ...
}
II. Configuration content : la clé d’un scan précis
Le JIT est efficace seulement si content est bien configuré.
content indique quels fichiers Tailwind scanne pour extraire les classes. Mal réglé : styles manquants (portée trop étroite) ou CSS gonflé (portée trop large).
2.1 Bases de la config content
La syntaxe de base :
// tailwind.config.js
module.exports = {
content: [
'./src/**/*.{html,js,jsx,ts,tsx}', // tous les templates sous src
],
// ...
}
Ici, ** signifie n’importe quel niveau de répertoire ; *.{html,js,jsx,ts,tsx} filtre par extension.
Selon le framework, adaptez les chemins :
// Projet Next.js
content: [
'./pages/**/*.{js,ts,jsx,tsx}',
'./components/**/*.{js,ts,jsx,tsx}',
'./app/**/*.{js,ts,jsx,tsx}', // App Router
]
// Projet Astro
content: [
'./src/**/*.{astro,html,js,jsx,ts,tsx}',
]
L’essentiel : couvrir tous les fichiers qui utilisent des classes Tailwind. Omettre un répertoire, et les styles de ce dossier ne seront pas générés.
2.2 Pièges que j’ai rencontrés
Piège 1 : glob trop large
Pour « simplifier », j’avais écrit :
content: [
'./**/*.js', // scanne node_modules !
]
Tailwind a parcouru tous les JS de node_modules ; le build a explosé, avec des styles absurdes générés en plus.
Limitez la portée :
content: [
'./src/**/*.js', // src uniquement
'./components/**/*.js', // components uniquement
]
Piège 2 : répertoire de composants oublié
Après une refacto, les composants étaient dans ./lib/components/. J’avais oublié de mettre à jour content ; les styles des nouveaux emplacements avaient disparu.
La leçon : à chaque changement de structure, synchronisez content.
Piège 3 : classes construites dynamiquement
Ce genre de code :
const color = 'red';
const className = `text-${color}-500`; // non détecté par le JIT
Le JIT voit une chaîne template, pas un nom de classe complet. En production, le style disparaît.
Solution : safelist (voir plus bas) ou syntaxe par objet :
const colors = {
red: 'text-red-500',
blue: 'text-blue-500',
};
const className = colors[color]; // nom complet, détectable
2.3 safelist et classes dynamiques
Quand les classes dynamiques sont inévitables, safelist entre en jeu.
// tailwind.config.js
module.exports = {
safelist: [
'text-red-500',
'text-blue-500',
'bg-red-500',
// ou regex pour un groupe de classes
{
pattern: /text-(red|blue|green)-(500|600)/,
variants: ['hover', 'focus'], // conserver les variantes
},
],
}
safelist force Tailwind à générer ces styles même s’ils n’apparaissent pas tels quels dans les templates.
Attention : plus la safelist est longue, plus le CSS grossit. Réservez-la aux cas nécessaires ; ne la transformez pas en « coffre-fort » pour toutes les classes possibles.
III. Contrôle du volume en production : stratégie en quatre couches
Le JIT rend le CSS léger en dev, mais la production mérite encore plus d’optimisation.
Voici une stratégie en quatre couches, de la config à la compression.
3.1 Couche 1 : config content précise
C’est la base, déjà couverte.
Principe : ne scanner que les fichiers qui utilisent Tailwind. Plus la portée est précise, plus le build est rapide et le CSS petit.
// Bon : portée précise
content: [
'./src/components/**/*.jsx',
'./src/pages/**/*.tsx',
]
// Mauvais : portée trop large
content: [
'./**/*.js', // scanne node_modules
]
3.2 Couche 2 : suppression automatique PurgeCSS
Tailwind v3+ active PurgeCSS en build de production pour retirer les styles inutilisés.
Assurez-vous que les commandes distinguent dev et production :
# Build dev (ne supprime pas les styles inutilisés)
npm run dev
# Build production (PurgeCSS automatique)
npm run build
Avec PostCSS, contrôle explicite possible :
// postcss.config.js
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
...(process.env.NODE_ENV === 'production' ? { cssnano: {} } : {}),
},
}
3.3 Couche 3 : Minify cssnano
Après PurgeCSS, cssnano compresse encore le CSS.
Compression : suppression des commentaires, fusion des règles dupliquées, simplification des sélecteurs, réduction des valeurs, etc.
# Minify direct avec Tailwind CLI
npx tailwindcss -i ./src/input.css -o ./dist/output.css --minify
# ou via PostCSS (voir ci-dessus)
Chiffre concret : mon projet est passé de 150 Ko (après PurgeCSS) à 45 Ko (après minify).
3.4 Couche 4 : compression réseau Brotli/Gzip
Ce n’est pas l’optimisation du CSS lui-même, mais du transfert.
Brotli ou Gzip sur les assets statiques réduit le CSS de 60 à 80 %.
# Brotli dans Nginx (module ngx_brotli requis)
brotli on;
brotli_comp_level 6;
brotli_types text/css application/javascript;
# ou Gzip (support natif Nginx)
gzip on;
gzip_comp_level 6;
gzip_types text/css application/javascript;
Comparaison : un CSS de 45 Ko tombe à environ 8 Ko en transfert Brotli.
Quand Netflix annonce 6,5 Ko de CSS, il s’agit du volume transmis après Brotli, pas de la taille du fichier brut.
IV. Cas pratique et comparaison de données
4.1 Avant / après optimisation
Franchement, ces chiffres m’ont surpris.
4.2 Dépannage des problèmes courants
Styles manquants ?
Étape 1 : vérifiez content — tous les fichiers avec classes Tailwind doivent être couverts.
Étape 2 : classes dynamiques ? Ajoutez safelist si besoin.
Étape 3 : confirmez un build production (npm run build), pas dev.
CSS encore trop lourd ?
Vérifiez une safelist trop longue, du CSS tiers mélangé au build Tailwind, ou une portée content trop large.
DevTools qui rame ?
Confirmez Tailwind ≥3 (JIT par défaut). Affinez content. Sur v2, migrez ou activez JIT manuellement.
V. Nouveautés Tailwind v4
Après l’existant, regardons Tailwind v4 (fin 2024).
5.1 Moteur Oxide
La mise à jour la plus enthousiasmante : Tailwind a réécrit son moteur en Rust.
Donnée officielle : builds incrémentaux 182 fois plus rapides. Changer une classe : secondes avant, millisecondes maintenant.
Oxide met en cache le scan de fichiers et ne retraite que ce qui change. Sur un gros projet (200+ composants), un build de ~10 s devient quasi instantané.
5.2 Objectif zéro configuration
Tailwind v4 pousse l’idée : la plupart des projets n’ont plus besoin de tailwind.config.js.
La config par défaut couvre les besoins courants : CSS moderne, container queries, breakpoints raisonnables, palette complète. Fichier de config seulement pour une personnalisation poussée.
Les nouveaux projets démarrent plus vite, avec moins de risques d’erreur de config.
Pour migrer vers v4 : la syntaxe évolue. Par exemple, theme.extend.colors cède la place aux propriétés CSS personnalisées. Consultez le guide de migration officiel avant de basculer.
Synthèse
Après cette nuit de crise à trois heures du matin, j’ai repassé toute la config Tailwind du projet au peigne fin.
Le JIT aligne dev et prod sur un CSS léger ; content fixe la portée du scan ; quatre couches d’optimisation ramènent le CSS du Mo au Ko. Avec Oxide en v4, la vitesse de build n’est plus un goulot.
Si vous êtes encore en mode traditionnel ou doutez de content, vérifiez d’abord :
- Tailwind ≥3 (JIT par défaut)
- content couvre précisément tous les templates
- build production avec PurgeCSS et cssnano
- serveur avec Brotli/Gzip
Après ces ajustements, vous devriez voir un gain net.
Des questions ? Laissez un commentaire, ou parcourez la doc officielle JIT et optimisation production — elle est claire.
Références
- Documentation Tailwind CSS Just-in-Time Mode
- Documentation Optimizing for Production
- Just-In-Time: The Next Generation of Tailwind CSS
- Annonce Tailwind CSS v4.0
- Tailwind CSS Best Practices for Performance Optimization
Configuration d'optimisation des performances Tailwind CSS
Flux de configuration complet, de l'activation du mode JIT au contrôle du volume en production
⏱️ Estimated time: 30 min
- 1
Step 1: Vérifier la version de Tailwind
Contrôlez la version de Tailwind CSS du projet :
• Tailwind v3+ active le mode JIT par défaut
• Tailwind v2 nécessite d'ajouter manuellement mode: 'jit' dans la config
• Il est recommandé de migrer vers v3+ pour de meilleures performances - 2
Step 2: Configurer les chemins de scan content
Définissez des chemins de scan précis dans tailwind.config.js :
• Next.js : ['./pages/**/*.{js,ts,jsx,tsx}', './components/**/*.{js,ts,jsx,tsx}']
• Astro : ['./src/**/*.{astro,html,js,jsx,ts,tsx}']
• Évitez les glob trop larges comme './**/*.js' - 3
Step 3: Gérer les noms de classes dynamiques
Pour les classes construites dynamiquement, utilisez safelist pour forcer la génération :
• Ajoutez les noms de classes complets dans le tableau safelist
• Utilisez pattern pour faire correspondre un groupe de classes par regex
• Combinez avec variants pour conserver hover, focus, etc. - 4
Step 4: Configurer l'optimisation du build de production
Ajoutez cssnano dans la config PostCSS :
• Ne pas activer cssnano en développement (build plus rapide)
• Activer automatiquement cssnano minify en production
• Utiliser process.env.NODE_ENV pour contrôler l'activation - 5
Step 5: Configurer la compression serveur
Configurez Brotli ou Gzip dans Nginx :
• Brotli : brotli on; brotli_comp_level 6;
• Gzip : gzip on; gzip_comp_level 6;
• Inclure les types text/css et application/javascript
FAQ
Comment activer le mode JIT dans Tailwind v3 ?
Quels problèmes cause l'omission de fichiers dans la config content ?
Pourquoi les noms de classes dynamiques échappent au JIT ?
Les 6,5 Ko de CSS de Netflix sont-ils le volume brut ou compressé ?
Quelles améliorations apporte le moteur Oxide de Tailwind v4 ?
Quel impact d'une safelist trop volumineuse ?
9 min de lecture · Publié le: 30 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
Dialog, Sheet, Popover : accessibilité et gestion du focus des composants en surcouche
Analyse approfondie de l'accessibilité et de la gestion du focus pour Dialog, Sheet et Popover dans shadcn/ui : normes WCAG, attributs ARIA, navigation clavier, piège à focus, avec exemples de code complets
Partie 10 sur 14
Suivant
Astro + Tailwind : configurer les styles sans conflit avec les composants islands
Conflits de styles Tailwind CSS avec l'architecture islands d'Astro ? Ce guide explique astro-island/astro-slot, l'intégration correcte de Tailwind v4 et quatre scénarios courants de conflits CSS avec leurs solutions.
Partie 12 sur 14



Commentaires
Connectez-vous avec GitHub pour laisser un commentaire