Accéder au contenu principal

Plan de migration vers Tailwind CSS v4 🚀 : la mĂ©thode (presque) sans douleur

Ça y est, le grand jour est arrivé ! Vous avez enfin dĂ©cidĂ© de vous attaquer Ă  cette fameuse dette technique qui vous fait faire des cauchemars la nuit. 😅

Beaucoup de nos projets (et sans doute les vĂŽtres) reposent encore sur d’anciens frameworks CSS basĂ©s sur Sass, comme Bootstrap v4 ou d’autres solutions maison (coucou Atomic Builder 👋). Et soyons honnĂȘtes : maintenir et mettre Ă  jour ces projets relĂšve souvent du parcours du combattant. On fait face Ă  un manque cruel de flexibilitĂ©, la dette technique s’accumule, et les dĂ©pendances commencent Ă  poser plus de soucis qu’elles n’en rĂ©solvent.

Sans oublier que Sass, bien qu’ayant Ă©tĂ© notre fidĂšle compagnon pendant de trĂšs (trĂšs) nombreuses annĂ©es, devient de moins en moins indispensable avec l’évolution fulgurante du CSS natif. Nous avons d’ailleurs eu l’occasion d’en parler dans notre article expliquant pourquoi passer Ă  PostCSS.

Le choix s’est donc naturellement portĂ© vers Tailwind CSS v4. C’est une solution qui a fait ses preuves chez JoliCode (J’ai testĂ© Tailwind CSS) et, cerise sur le gĂąteau, cette nouvelle version ne nĂ©cessite aucune dĂ©pendance liĂ©e Ă  Sass.

L’annĂ©e derniĂšre, nous avons amorcĂ© des phases de migration pour plusieurs de nos projets clients. Aujourd’hui, j’ai envie de partager avec vous quelques retours d’expĂ©rience et une mĂ©thodologie (testĂ©e et approuvĂ©e ✅) pour que ces migrations se passent le mieux possible !

Section intitulĂ©e phase-1-migration-des-feuilles-de-styles-cssPhase 1 : Migration des feuilles de styles CSS 🎹

L’objectif de cette premiĂšre phase est simple : utiliser du CSS natif et dire officiellement au revoir Ă  notre bon vieux Sass. 👋

La toute premiÚre étape consiste à migrer la configuration globale de votre projet (généralement définie dans des fichiers tels que variables.scss ou global.scss) vers un systÚme basé sur des custom properties (variables CSS), en ciblant la racine du document HTML via la pseudo-classe :root.

Avant (Sass) :

$color-primary: #f7d325;
$color-secondary: #ff2951;
$font-family-sans-serif: "Source Sans Pro", sans-serif;

AprĂšs (CSS natif) :

:root {
  --color-primary: #f7d325;
  --color-secondary: #ff2951;
  --font-sans: "Source Sans Pro", sans-serif;
}

Info


Utilisez dĂšs maintenant la nomenclature de Tailwind CSS v4 pour nommer vos variables CSS. Ça vous fera gagner un temps prĂ©cieux pour la suite. 👌

Section intitulĂ©e cas-n-1-les-variables-et-fonctionsCas n°1 : Les variables et fonctions

Une fois votre thùme mis en place, votre premiùre mission sera de remplacer tous vos $ par des var(--). C’est aussi l’occasion de traduire vos fonctions Sass en CSS moderne. 👀

Avant (Sass) :

.button {
  width: math.div(100%, 3);
  background-color: $color-primary;
  
  &:hover,
  &:focus-visible,
  &:active {
    background-color: darken($color-primary, 15%);
  }
}

AprĂšs (CSS natif) :

.button {
  /* Le CSS natif s'occupe des calculs dynamiquement ! */
  width: calc(100% / 3);
  background-color: var(--color-primary);
  
  &:hover,
  &:focus-visible,
  &:active {
    /* Magie ! Les couleurs relatives en CSS natif */
    background-color: hsl(from var(--color-primary) h s calc(l - 15)); 
  }
}

Aujourd’hui, le CSS natif est devenu suffisamment mature pour remplacer la quasi-totalitĂ© des fonctions Sass. C’est particuliĂšrement vrai pour les manipulations de couleurs, qui s’écrivent dĂ©sormais trĂšs simplement grĂące aux couleurs relatives en CSS. 🎹

Section intitulĂ©e cas-n-2-le-piege-du-selecteur-d-imbrication-code-amp-code-et-du-bemCas n°2 : Le piĂšge du sĂ©lecteur d’imbrication & et du BEM

La bonne nouvelle, c’est que le CSS natif gĂšre dĂ©sormais trĂšs bien le nesting (l’imbrication). L’esperluette (&) pour cibler des Ă©tats comme &:hover ou &:focus fonctionne parfaitement sans Sass.

La mauvaise nouvelle ? Si vous utilisiez le & pour concatĂ©ner des classes, typiquement avec la mĂ©thodologie BEM (&__element ou &--modifier), le CSS natif ne comprendra pas cette syntaxe. Il va falloir « dĂ©simbriquer Â» ces Ă©lĂ©ments.

Avant (Sass) :

.link {
  color: $color-primary;
  
  &:hover,
  &:focus-visible,
  &:active {
    color: $color-secondary;
  }

  /* Sass va compiler ce code en ".link--secondary" */
  &--secondary {
    color: $color-secondary;
  }
}

AprĂšs (CSS natif) :

.link {
  color: var(--color-primary);
  
  /* Ce code fonctionne toujours en CSS natif ! */
  &:hover,
  &:focus-visible,
  &:active {
    color: var(--color-secondary);
  }
}

/* Il faut sortir la classe enfant de l'imbrication */
.link--secondary {
  color: var(--color-secondary);
}

Section intitulĂ©e cas-n-3-les-media-queriesCas n°3 : Les media queries

Pour les media queries gĂ©nĂ©rĂ©es via des mixins ou des fonctions Sass (du type @include media-breakpoint-up(md)), passez simplement les valeurs en dur pour le moment (@media (min-width: 768px)). Nous nous en occuperons plus tard, lors de l’intĂ©gration de Tailwind.

Section intitulĂ©e cas-n-4-les-mixins-boucles-et-regles-complexesCas n°4 : Les mixins, boucles et rĂšgles complexes

Pour les cas trÚs spécifiques (boucles @for, mixins complexes), la solution la plus pragmatique est de récupérer la version déjà compilée et de la coller dans votre fichier CSS.

Avant (Sass) :

@for $i from 1 through 3 {
  .button--size-#{$i} {
    padding: #{$i}rem;
  }
}

AprĂšs (CSS natif) :

.button--size-1 { padding: 1rem; }
.button--size-2 { padding: 2rem; }
.button--size-3 { padding: 3rem; }

À la fin de cette phase, le code CSS de votre projet n’utilise techniquement plus aucune fonctionnalitĂ© propre Ă  Sass. 👏

Section intitulĂ©e phase-2-migration-provisoire-des-classes-utilitairesPhase 2 : Migration (provisoire) des classes utilitaires 🧰

C’est l’étape de la « prise de masse Â» avant la sĂšche. đŸ’Ș

L’idĂ©e est de rĂ©cupĂ©rer le CSS compilĂ© de toutes les classes utilitaires de votre ancien framework et de les stocker dans un nouveau dossier, par exemple utilities/. Pour garder l’esprit clair, sĂ©parez-les par thĂ©matique : utilities/typography.css, utilities/spacing.css, etc.

Exemple d’un fichier utilities/spacing.css (rĂ©cupĂ©rĂ© depuis Bootstrap v4) :

.mt-1 { margin-top: 0.25rem !important; }
.mt-2 { margin-top: 0.5rem !important; }
.mb-3 { margin-bottom: 1rem !important; }
/* ... */

Votre CSS global va grossir temporairement. C’est normal, ne paniquez pas ! Ces fichiers agiront comme un filet de sĂ©curitĂ© visuel en attendant que Tailwind prenne le relais. 😼‍💹

Section intitulĂ©e phase-3-on-debranche-l-ancien-framework-cssPhase 3 : On dĂ©branche l’ancien framework CSS 💔

Si les phases 1 et 2 ont Ă©tĂ© faites minutieusement, vous pouvez supprimer l’ancien framework CSS de vos dĂ©pendances. Visuellement, rien ne devrait bouger. đŸ€ž

Avertissement


Attention aux comportements JS ! Si votre ancien framework (comme Bootstrap) gĂ©rait des modales, des info-bulles ou des menus dĂ©roulants, la suppression de son CSS (et de ses scripts associĂ©s) risque de casser les animations ou le positionnement. PrĂ©voyez un peu de temps de dĂ©veloppement pour vĂ©rifier les interactions JavaScript et réécrire ces quelques composants. Profitez-en pour utiliser du JS vanilla ou du CSS moderne (l’API Popover native est parfaite pour ça, par exemple !).

Section intitulĂ©e phase-4-l-adieu-a-sassPhase 4 : L’adieu Ă  Sass đŸ«Ą

C’est l’heure de dĂ©sinstaller une fois pour toutes sass (ou node-sass). N’oubliez pas de renommer tous vos fichiers .scss en .css.

Lors de cette Ă©tape, il est trĂšs probable que le compilateur Ă©choue lors de son premier lancement. Si la console se remplit d’erreurs, pas de panique, c’est un grand classique ! Cela s’explique gĂ©nĂ©ralement par l’une de ces trois raisons :

  1. L’import fantĂŽme : Votre bundler (comme Webpack) ou votre point d’entrĂ©e JavaScript (le fameux app.js) pointe toujours vers un fichier portant l’extension .scss. Pensez Ă  bien mettre Ă  jour vos chemins d’importation.
  2. Le reliquat de Sass : Il reste quelques $, @use, etc. qui traĂźnent dans vos fichiers CSS. Pensez Ă  les supprimer.
  3. Les commentaires : Les commentaires d’une seule ligne Ă©crits avec // Ă©taient valides avec Sass, mais pas avec votre CSS natif.

L’erreur classique Ă  corriger :

// Ce commentaire était valide en Sass, mais fera planter votre CSS natif !
.element { color: var(--color-primary); }

/* Remplacez-le par la syntaxe standard ! */
.element { color: var(--color-primary); }

Une fois ces petits ajustements faits, respirez un grand coup. Le plus dur techniquement est derriùre vous. 🎉

Section intitulĂ©e phase-5-l-entree-en-scene-de-tailwind-css-v4Phase 5 : L’entrĂ©e en scĂšne de Tailwind CSS v4 đŸ€©

Il est enfin temps d’installer Tailwind CSS v4 et PostCSS (indispensable dans nos projets Symfony avec Webpack Encore). Je vous conseille de suivre la documentation officielle pour le setup initial.

Section intitulĂ©e le-piege-de-l-import-global-et-du-preflightLe piĂšge de l’import global (et du Preflight)

La documentation officielle vous recommandera d’importer Tailwind de cette façon :

@import "tailwindcss";

En utilisant cet import global, Tailwind embarque par dĂ©faut plusieurs layers CSS (theme, base, components et utilities), injectant par la mĂȘme occasion son propre reset CSS (Preflight). Si votre projet possĂ©dait dĂ©jĂ  un fichier de reset (comme normalize.css), vous risquez d’avoir des conflits.

Info


DĂ©sactivez Preflight dans un premier temps, ainsi que l’ensemble des layers CSS importĂ©s pour limiter les rĂ©gressions et les problĂ©matiques liĂ©es Ă  la cascade CSS.

Pour cela, privilĂ©giez des imports ciblĂ©s (sans les layers CSS) :

@import "tailwindcss/theme.css";
@import "tailwindcss/utilities.css";

Section intitulée la-magie-de-la-directive-code-theme-codeLa magie de la directive @theme

La rĂ©volution de la v4, c’est qu’elle est CSS-first. Fini l’énorme fichier tailwind.config.js Ă  la racine de votre projet ! Le thĂšme que vous aviez anticipĂ© lors de la phase 1 s’intĂšgre dĂ©sormais presque nativement grĂące Ă  la nouvelle directive @theme.

Avant :

:root {
  --color-primary: #f7d325;
  --color-secondary: #ff2951;
  --font-sans: "Source Sans Pro", sans-serif;
}

AprĂšs :

@theme static {
  --color-primary: #f7d325;
  --color-secondary: #ff2951;
  --font-sans: "Source Sans Pro", sans-serif;
}

Info


Gardez vos variables CSS accessibles partout ! Pensez Ă  gĂ©nĂ©rer vos variables CSS avec le comportement static, comme indiquĂ© dans la documentation Tailwind. Ainsi, elles ne seront pas limitĂ©es aux classes utilitaires de Tailwind, mais resteront utilisables partout dans vos propres composants CSS personnalisĂ©s.

C’est aussi le moment parfait pour utiliser la directive @variant afin d’uniformiser ces fameuses media queries que nous avions mises en dur plus tît !

Avant :

@media (min-width: 768px) {
  .card {
    color: var(--color-primary);
  }
}

AprĂšs :

@variant md {
  .card {
    color: var(--color-primary);
  }
}

Ce petit changement vous garantit que tout votre CSS sur-mesure restera parfaitement synchronisé avec le comportement natif des classes utilitaires de Tailwind.

Section intitulĂ©e phase-6-le-nettoyage-de-printempsPhase 6 : Le nettoyage de printemps đŸ§č

Je prĂ©fĂšre ĂȘtre honnĂȘte : cette Ă©tape demande de la patience. 🙃

L’objectif est de supprimer le dossier utilities/ créé Ă  la phase 2. Pour ce faire, vous allez devoir remplacer dans tous vos templates HTML/Twig les anciennes classes par les nouvelles gĂ©nĂ©rĂ©es par Tailwind.

Vos meilleurs alliĂ©s ici seront l’outil de recherche de votre IDE, les expressions rĂ©guliĂšres (Regex), et bien sĂ»r votre LLM (Large Language Model) favori (ChatGPT, Claude, GitHub Copilot, etc.) pour automatiser un maximum le processus.

Avant (Bootstrap v4) :

<div class="d-flex flex-column flex-md-row">...</div>

AprĂšs (Tailwind CSS v4) :

<div class="flex flex-col md:flex-row">...</div>

Section intitulĂ©e le-boss-final-les-grillesLe boss final : Les grilles 😎

Il n’y a pas de solution magique ici. Les vieux frameworks utilisaient gĂ©nĂ©ralement Flexbox pour simuler un comportement de grille. Tailwind, lui, utilise le module natif CSS Grid Layout (modĂšle de disposition en grille).

Il va falloir repasser sur vos grilles manuellement. 😬

L’ancienne approche (Flexbox) :

<div class="row">
  <div class="col-12 col-md-6">...</div>
  <div class="col-12 col-md-6">...</div>
</div>

La nouvelle approche (Grid) :

<div class="grid grid-cols-1 md:grid-cols-2">
  <div>...</div>
  <div>...</div>
</div>

C’est fastidieux, mais le DOM en ressort considĂ©rablement allĂ©gĂ© et plus lisible. đŸ„ł

Section intitulĂ©e conclusion-tout-ca-pour-caConclusion : Tout ça pour ça ? đŸ€”

Oui, mille fois oui. Migrer vers Tailwind CSS v4 n’est pas un parcours de santĂ© pour un projet existant. Mais les avantages sont colossaux.

Vous dites adieu Ă  l’usine Ă  gaz qu’était devenu Sass au fil des annĂ©es. Le poids final de votre CSS sera drastiquement rĂ©duit puisque Tailwind ne compile que ce que vous utilisez rĂ©ellement. Sans parler des performances pures : avec son nouveau moteur Ă©crit en Rust, les temps de compilation sont si rapides qu’on les remarque Ă  peine.

Enfin, la Developer Experience (DX) de vos Ă©quipes s’en trouvera transformĂ©e. C’est un investissement en temps consĂ©quent, mais c’est un cadeau inestimable que vous faites au futur de votre projet. 🎁

Section intitulĂ©e et-concretement-comment-on-vend-ca-a-sa-directionEt concrĂštement, comment on vend ça Ă  sa direction ?

C’est souvent la question qui fĂąche. On sait que le chantier est nĂ©cessaire, mais il est difficile d’estimer le temps que cela va prendre sans y laisser des plumes, d’oĂč l’effet tunnel qui effraie les Ă©quipes produit.

Pour dĂ©bloquer la situation, nous avons l’habitude chez JoliCode de commencer par un audit flash (1 Ă  2 jours). L’objectif est de poser les choses Ă  plat pour vous fournir un plan de bataille concret Ă  dĂ©fendre en interne :

  1. Un état des lieux clair de la dette front actuelle (dépendances, risques, obsolescence).
  2. Une estimation chiffrée de la migration, découpée par phase.
  3. Un plan de déploiement progressif qui ne bloque pas votre roadmap produit.
  4. Les bénéfices attendus (gains de performance, vélocité des équipes, etc.).

Si vous avez besoin d’aide pour cadrer votre propre migration, n’hĂ©sitez pas Ă  nous faire signe !

J’espĂšre que ce retour d’expĂ©rience vous sera utile et vous donnera le courage de sauter le pas. N’hĂ©sitez pas Ă  partager vos propres astuces ou vos galĂšres de migration dans les commentaires ! 🙂

Commentaires et discussions

Ces clients ont profité de notre expertise