Migration SCSS : de @import vers @use avec Dart Sass
Depuis l’arrivée de Dart Sass, l’écosystème SCSS a franchi un cap décisif. Ce moteur est aujourd’hui la version de référence, celle qui définit l’avenir du langage. Il remplace les anciens compilateurs Ruby ou LibSass, désormais figés, et introduit une nouvelle manière de penser le code : modulaire, structurée, et prévisible.
Avant, la directive @import fusionnait tous nos fichiers dans un même espace global. C’était pratique, mais confus : les variables se mélangeaient, les mixins se chevauchaient, et une simple modification pouvait affecter tout le projet sans qu’on sache pourquoi.
Avec @use, Dart Sass change la logique. Chaque fichier devient un module autonome, doté de son propre espace de noms. Les variables, fonctions et mixins n’appartiennent plus à un tout indistinct, mais à un domaine précis. On ne parle plus d’inclusion, mais de dépendance explicite.
Ce passage à @use n’est pas qu’une question de syntaxe : c’est une évolution de fond. Il permet d’organiser le code comme une bibliothèque de composants réutilisables, testables, et documentables. Et surtout, il ouvre la voie à des systèmes de styles vraiment modulaires, où chaque bloc peut vivre seul, être partagé, ou remplacé sans tout casser.
Comprendre la fin de @import
Avant @use, Sass fonctionnait comme une grande feuille de style découpée en morceaux. Chaque fichier importé avec @import venait s’ajouter au flux global, sans distinction d’origine ni de portée. C’était commode au départ, car on pouvait simplement empiler les fichiers : variables, mixins, composants, thèmes… tout finissait dans le même espace.
// Ancienne méthode
@import 'variables';
@import 'mixins';
@import 'layout';Sous le capot, Dart Sass injectait le contenu de chaque fichier dans la même portée. Ainsi, une variable déclarée dans _variables.scss devenait accessible partout, y compris dans _layout.scss.
// _variables.scss
$base-color: #4472c4;
// _layout.scss
body { background: $base-color; }Cette fusion totale rendait le code difficile à maintenir : le moindre renommage ou la moindre surcharge de variable pouvait avoir des effets en cascade. En ajoutant un second module importé comme @import 'colors';, cette nouvelle définition écrasait silencieusement la précédente issue de _variables.scss. Le résultat final dépendait donc de l’ordre des imports.
// _colors.scss
$base-color: #ff0000; // redéfinit la même variableL’autre limite, plus subtile, concernait la compilation elle-même : plus un projet grandissait, plus les inclusions se multipliaient. Chaque @import déclenchait une nouvelle lecture de fichier. Sur de gros ensembles, la compilation pouvait devenir lente et imprévisible.
C’est pour corriger cette approche que Dart Sass a introduit @use. Ce n’est pas seulement un changement d’ordre technique, mais un changement de philosophie : on ne fusionne plus, on relie.
Pourquoi @use change tout
Avec @use, Sass change de logique : chaque fichier devient un module autonome. Lorsqu’on appelle un fichier avec @use, son contenu n’est plus injecté dans l’espace global, mais chargé une seule fois, dans son propre contexte. Ce simple principe transforme profondément la manière de structurer un projet.
// Nouvelle méthode
@use 'variables';
body {
background: variables.$base-color;
}Ici, la variable $base-color n’existe plus partout : elle appartient désormais au module variables. Pour y accéder, on précise son espace de noms. Cela peut sembler plus long à écrire, mais cette précision change tout.
Chaque module vit dans son périmètre ; il expose uniquement ce qu’il contient, sans polluer le reste du projet. On gagne en stabilité, en lisibilité, et en sécurité.
Ce cloisonnement ouvre aussi de nouvelles possibilités : on peut charger sélectivement un thème, isoler des palettes de couleurs, ou même créer plusieurs variantes d’un design sans tout dupliquer.
// theme.scss
@use 'colors' as light;
@use 'colors-dark' as dark;
body.light { color: light.$text; }
body.dark { color: dark.$text; }@use ne remplace pas seulement @import : il donne à Sass une vraie modularité. C’est un langage de styles qui se rapproche des logiques d’architecture logicielle : chaque fichier peut être testé, réutilisé, ou combiné sans casser les autres.
De plus, Sass garantit qu’un même module n’est chargé qu’une seule fois, même s’il est appelé plusieurs fois avec @use. Cela évite les redéfinitions involontaires et allège la compilation. Là où @import réinjectait le contenu à chaque inclusion, @use établit un lien unique et durable entre les fichiers, rendant l’ensemble plus stable et prévisible.
Migrer sans tout casser
Passer de @import à @use ne se fait pas en un clic, mais c’est une transition maîtrisable. L’objectif est de conserver l’existant tout en adoptant la nouvelle logique modulaire. Pour l’instant, Dart Sass maintient encore la compatibilité avec @import pour assurer une transition en douceur : l’instruction fonctionne toujours, mais génère désormais un avertissement lors de la compilation. Cela permet de conserver d’anciens projets tout en préparant leur évolution vers la nouvelle syntaxe.
Donc on commence souvent par remplacer les anciennes directives :
// Avant
@import 'variables';
@import 'mixins';
// Après
@use 'variables';
@use 'mixins';Avec @use, Sass crée automatiquement un espace de noms pour chaque fichier. Par défaut, cet espace reprend le nom du fichier lui-même :
// Ancien code
body { background: $base-color; }
// Nouveau code
body { background: variables.$base-color; }Mais on peut aussi attribuer un alias pour simplifier ou clarifier la lecture. L’alias agit comme un raccourci lisible qui permet d’appeler les éléments d’un module sans répéter le nom complet du fichier. C’est particulièrement utile lorsque l’on travaille avec plusieurs fichiers similaires, par exemple variables, mixins, layout, colors, dont les noms seraient trop longs ou trop proches pour être distingués d’un coup d’œil. En leur donnant chacun un alias cohérent (vars, mix, lay, clr), on obtient une lecture de code plus fluide et mieux hiérarchisée :
@use 'variables' as vars;
@use 'mixins' as mix;
@use 'layout' as lay;
.header {
color: vars.$primary;
@include mix.centered;
margin: lay.$spacing-lg;
}Et pour assurer une migration douce, Sass autorise un mode temporaire en employant *. Ce mode permet de continuer à utiliser les variables sans préfixe, comme avec @import. Il agit comme un pont entre l’ancien et le nouveau fonctionnement : tout le contenu du module reste accessible globalement, ce qui facilite la transition dans les projets volumineux ou anciens.
@use 'variables' as *;Cependant, cette solution doit rester provisoire : elle contourne l’isolation voulue par Dart Sass et retarde la pleine adoption de la modularité. Une fois la migration stabilisée, mieux vaut revenir à une structure claire avec des alias explicites.
L’intérêt de cette migration est qu’elle permet, à terme, de mieux structurer son architecture : chaque module devient testable isolément, et la maintenance gagne en clarté.
En migrant progressivement, on transforme peu à peu un ensemble de fichiers liés en un véritable système modulaire.
Les variables de configuration avec with
@use ne se limite pas à importer un module : il permet aussi de le configurer avant son chargement. Grâce à la clause with, on peut modifier certaines variables déclarées comme configurables dans le fichier importé. Cela évite d’avoir à dupliquer ou à éditer les fichiers sources, tout en adaptant leur comportement au contexte du projet. Prenons un exemple simple :
// _theme.scss
$primary: #4472c4 !default;
$radius: 4px !default;
.button {
background: $primary;
border-radius: $radius;
}Le mot-clé !default indique que ces variables peuvent être redéfinies depuis l’extérieur. On peut alors les surcharger au moment du @use :
// main.scss
@use 'theme' with (
$primary: #f5a623,
$radius: 6px
);Ainsi, le même module devient paramétrable selon le besoin : un thème clair, sombre ou personnalisé, sans avoir à toucher au fichier d’origine. Ce système offre une vraie souplesse :
- Avantage : il centralise la configuration sans altérer le code partagé.
- Inconvénient : les variables configurables doivent avoir été déclarées avec
!default, sinon elles ne pourront pas être redéfinies.
C’est une approche élégante pour concevoir des design systems ou des thèmes Sass modulaires, où la configuration s’effectue à l’import plutôt qu’à la modification des fichiers.
L’organisation modulaire avec @forward
Afin de pouvoir décrypter la directive @forward, situons d’abord les fichiers sources dans leur arborescence afin de mieux appréhender l’organisation des fichiers. Cette vue d’ensemble pourra servir à illustrer le fonctionnement de @forward.
scss/
├── config/
│ ├── _variables.scss
│ ├── _layout.scss
│ ├── _colors.scss
│ └── _mixins.scss
└── main.scssLe dossier config/ contient les fichiers de base : couleurs, espacements, affichage, mixins, etc. Le fichier main.scss, situé à la racine, sert de point d’entrée pour la compilation finale. Jusqu’ici, chaque fichier devait être importé individuellement :
// main.scss
@use 'config/variables';
@use 'config/mixins';
/* ainsi que tous l'ensemble des fichiers nécessaires */Donc à mesure que le projet grandit, ces appels se multiplient et deviennent vite lourds à maintenir. C’est là qu’intervient @forward. Cette directive permet de regrouper plusieurs fichiers Sass et d’en exposer une interface commune, autrement dit, un seul point d’accès vers plusieurs modules. Créons un nouveau fichier qui fera office de passerelle :
// config/_shared.scss
@forward 'variables';
@forward 'mixins';
/* ... */Désormais, le code principal peut se contenter d’un seul appel :
// main.scss
@use 'config/shared' as cfg;
.header {
color: cfg.$primary; // issu de _variables.scss
@include cfg.flex-center; // issu de _mixins.scss
}Dans cet exemple, $primary provient du fichier _variables.scss, tandis que le mixin flex-center vient de _mixins.scss. Le fichier _shared.scss ne contient pas de styles : il réexporte ce qu’il souhaite rendre disponible. Cela en fait une véritable interface de partage pour les autres fichiers Sass.
Il n’est pas obligatoire de nommer ce fichier _shared.scss : on peut choisir n’importe quel nom selon la logique du projet. Par contre, si le dossier contient un fichier _index.scss, Sass le chargera automatiquement quand on invoque simplement le dossier :
@use 'config' as cfg;Cette distinction permet d’adapter la structure à différents contextes : un projet unique, plusieurs sous-thèmes, ou un design system partagé. Enfin, @forward ne se contente pas de regrouper : il peut également contrôler ce qu’il expose. Avec hide, on peut masquer certaines variables ou mixins internes. Prenons un exemple : imaginons un module de calcul d’échelle pour gérer des tailles ou espacements dynamiques. :
// config/_scale.scss
$base-size: 1rem;
$ratio: 1.25; // valeur interne pour le calcul
@function scale($step) {
@return $base-size * pow($ratio, $step);
}
// config/_shared.scss
@forward 'variables';
@forward 'scale' hide $ratio;
// main.scss
@use 'config/shared' as cfg;
h1 { font-size: cfg.scale(2); } // Ok
p { font-size: cfg.$ratio; } // Erreur : $ratio est cachéeDans cet exemple, $ratio est une donnée technique utilisée uniquement pour les calculs internes, et il serait inutile, voire risqué, de l’exposer ailleurs. Grâce à hide, on protège cette logique interne tout en laissant accessible la fonction scale().
Lors de la compilation, Sass regroupe tous les fichiers forwardés une seule fois et génère un CSS propre et sans doublons. Ce mécanisme rend le code plus sûr et plus compréhensible pour toute l’équipe.
_partials.scss vs @forward
Les partials (_partials.scss) existent toujours : ce sont des fichiers Sass commençant par un underscore, que l’on inclut maintenant via @use ou @forward. Autrement dit, @forward ne remplace pas les partials, il s’appuie sur eux pour structurer le code et en contrôler la visibilité. Ainsi, les partials (_partials.scss) servent toujours de base, mais @forward leur donne un rôle plus structurant : il permet de définir clairement quels éléments d’un fichier doivent être exposés ou masqués, créant ainsi une hiérarchie lisible entre les modules Sass. Les partials sont simplement assemblés, alors qu’un fichier forwardé agit comme un point d’entrée qui définit ce qui doit être visible et ce qui reste interne. Cela renforce la logique de compilation et clarifie la responsabilité de chaque module Sass.
Gérer les collisions de noms avec @forward
Quand plusieurs modules exposent un élément portant le même nom, Sass refuse de choisir à votre place. Cela se produit par exemple si deux fichiers forwardés déclarent chacun une variable appelée $foo. Dans ce cas, l’accès via le point d’entrée commun échoue et Sass détecte que config/shared réexporte deux éléments portant le même nom. Le membre cfg.$foo serait ambigu. Par sécurité, Sass arrête la compilation et demande une résolution explicite.
// config/_variables.scss
$foo: steelblue;
// config/_layout.scss
$foo: tomato;
// config/_shared.scss
@forward 'variables';
@forward 'layout';
// main.scss
@use 'config/shared' as cfg;
.test { color: cfg.$foo; } // Erreur, collision de nomsTrois stratégies pour résoudre proprement. Lorsque plusieurs modules exportent des éléments portant le même nom, il ne s’agit pas d’un simple conflit syntaxique, mais d’un vrai choix d’architecture. Faut-il renommer, masquer ou séparer les modules ? Sass ne décide pas à votre place : à vous d’indiquer comment organiser la hiérarchie entre vos fichiers.
Renommer au moment du @forward afin de préfixer chaque famille et lever toute ambiguïté.
Avantage : rend immédiatement visibles les origines des éléments et évite tout conflit futur.
Inconvénient : alourdit parfois la syntaxe et demande une discipline stricte dans la nomenclature.
// config/_shared.scss
@forward 'variables' as vars-*;
@forward 'layout' as lay-*;
// main.scss
@use 'config/shared' as cfg;
.a { color: cfg.$vars-foo; }
.b { color: cfg.$lay-foo; }Masquer un membre en conflit avec hide si un seul doit être exposé publiquement.
Avantage : solution simple et rapide lorsqu’un seul élément doit rester accessible.
Inconvénient : risque de rendre certaines dépendances implicites, surtout dans les projets complexes.
// config/_shared.scss
@forward 'variables';
@forward 'layout' hide $foo;
// main.scss
@use 'config/shared' as cfg;
.ok { color: cfg.$foo; } // provient de variables.$fooÉviter la réexportation conflictuelle et consommer les modules séparément quand cela a du sens.
Avantage : maintient une séparation claire entre les domaines fonctionnels et limite les effets de bord.
Inconvénient : augmente légèrement le nombre d’imports et la maintenance si les modules sont nombreux.
// main.scss
@use 'config/variables' as vars;
@use 'config/layout' as lay;
.x { color: vars.$foo; }
.y { color: lay.$foo; }En résumé
| Référence | Accessible via le point d’entrée | Notes |
|---|---|---|
| variables.$foo | Oui | Toujours disponible dans son module source. |
| layout.$foo | Oui | Idem, disponible dans son module source. |
| cfg.$foo | Non | Erreur de compilation en cas d’homonymie forwardée. |
| cfg.$vars-foo | Oui | Accessible après renommage via as vars-*. |
| cfg.$lay-foo | Oui | Accessible après renommage via as lay-*. |
| cfg.$foo avec hide sur layout | Oui | Pointe vers variables.$foo si layout.$foo est masquée. |
| Si deux modules possèdent un membre homonyme, l’accès via le point d’entrée commun échoue. Il faut soit renommer, soit masquer, soit consommer séparément. Cela rend les dépendances explicites et fiabilisées. | ||
Configurer un module réexporté avec @forward with
Après avoir vu comment @use with permet de personnaliser un module pour soi, @forward with étend cette idée à l’échelle du partage.
Cette directive agit en amont : elle configure un module avant de le transmettre à d’autres fichiers. Là où @use with adapte un module localement, @forward with crée une version préconfigurée, prête à être utilisée ailleurs. Prenons l’exemple d’un module de thème :
// _theme.scss
$primary: #4472c4 !default;
$radius: 4px !default;
.button {
background: $primary;
border-radius: $radius;
}Plutôt que de redéfinir ces variables à chaque utilisation avec @use with, on peut créer une variante du module :
// _theme-dark.scss
@forward 'theme' with (
$primary: #222,
$radius: 6px
);Puis l’utiliser simplement :
// main.scss
@use 'theme-dark' as theme;Le fichier _theme-dark.scss agit comme un intermédiaire configuré : il réexporte le module theme, mais avec des valeurs déjà définies. Tous les fichiers qui l’emploieront bénéficieront de ces réglages par défaut, sans avoir à les redéclarer.
Pourquoi c’est utile ? @forward with est une excellente solution pour créer des ensembles Sass modulaires :
- un jeu de variables de base dans
theme, - plusieurs variantes (ex.
theme-light,theme-dark,theme-highcontrast), - et un point d’entrée global (
_themes.scss) qui regroupe ou sélectionne ces versions.
Cette approche est particulièrement adaptée aux design systems ou aux bibliothèques partagées, où l’on veut permettre la personnalisation sans modifier le cœur du code.
En résumé
| Directive | Portée | Moment d’application | Cas d’usage |
|---|---|---|---|
| @use with | Locale | Lors de l’import du module | Adapter un module pour un usage ponctuel ou spécifique à un projet. |
| @forward with | Globale | Avant la réexportation | Créer des variantes préconfigurées (thèmes, styles dérivés) à partager avec d’autres fichiers. |
| Résumé : @use with configure un module pour soi ; @forward with le configure pour les autres. Cette distinction permet de construire des architectures Sass flexibles et réutilisables. | |||
@forward withrend possible une forme de “composition Sass” : on n’hérite plus d’un style, on le paramètre à la source avant de le diffuser.
Une nouvelle manière de penser le style
Avec @use et @forward, Sass ne se contente plus de compiler du code : il structure la pensée du style. Ces directives transforment la manière dont nous concevons nos feuilles de style, en introduisant une logique de modularité et de responsabilité. Chaque fichier devient une unité autonome, reliée aux autres par des liens explicites.
Avant, un projet Sass ressemblait à une grande fresque continue où tout se mélangeait dans un même espace global. Les variables, mixins et fonctions coexistaient sans frontières, ce qui donnait une impression d’unité, mais reposait sur une base fragile. Aujourd’hui, grâce à la modularité, cette organisation devient réelle : les couleurs appartiennent à un module, les espacements à un autre, et les composants conservent leur propre domaine. Ce découpage rend le projet plus lisible, plus stable et surtout plus évolutif.

Cette approche rappelle la manière dont on structure une application logicielle : chaque partie a sa fonction et son périmètre. Le CSS devient ainsi un langage d’architecture. On ne parle plus seulement de mise en forme, mais d’organisation du design, de hiérarchie visuelle et de réutilisation maîtrisée.
Penser le style aujourd’hui, c’est penser en systèmes.
@useet@forwarddonnent les outils pour y parvenir, en favorisant un code clair, documenté et durable.
Dans les chapitres précédents, nous avons vu comment ces directives permettent de relier, regrouper et protéger les modules Sass. Ici, elles nous invitent à franchir une étape supplémentaire : concevoir le style non plus comme une succession de fichiers, mais comme un véritable langage de conception, capable d’évoluer, de se partager et de durer.
Conclusion
Adopter @use et @forward, c’est passer d’une logique d’empilement à une logique de système. Chaque module devient une brique claire et réutilisable, chaque dépendance une relation maîtrisée. Sass n’est plus seulement un compilateur, mais un outil d’architecture du design. Cette évolution nous rapproche d’un code plus transparent, transmissible et durable — un code qui, comme tout bon langage, sert à construire, pas à accumuler.
