Vincent Barrault

Faire un design system avec un pattern de thèmes en Sass

Faire un design system avec un pattern de thèmes en Sass

Table des matières

L'approche directe

Pour commencer mon design system, la première chose que je dois faire est de développer un composant.

Ici, pour l'exemple, je vais faire un simple bouton.

./src/components/_button.scss
@use '../config';

.button {
    background-color: config.$backgroundColor;
    color: config.$defaultColor;
}

Avec quelques couleurs dans un fichier de configuration

./src/_config.scss
$backgroundColor: white;
$defaultColor: black;

Enfin, je vais créer un fichier d'entrée ./style.scss

./style.scss
@use 'src/components/button';

Le résultat est là, quand j'exécute la commande sass style.scss output.css, j'obtiens le code suivant dans le fichier output.css:

./output.css
.button {
    background-color: white;
    color: black;
}

J'ai donc développé un design system avec un fichier _config.scss pour changer facilement les paramètre du design, et un dossier de composants.

La limite de la solution

Maintenant que j'ai mon design system, je voudrais faire un deuxième thème pour certaines parties de l'application.

Ces portions de l'interface devront être en couleur inversées, un peu comme un thème sombre.

Je commence donc à créer un fichier ./src/_config-dark.scss

./src/_config-dark.scss
$backgroundColor: black;
$defaultColor: white;

et je modifie mon composant comme ceci

./src/components/_button.scss
@use '../config';
@use '../config-dark';

.button {
    background-color: config.$backgroundColor;
    color: config-dark.$defaultColor;
}

.dark .button {
    background-color: config.$backgroundColor;
    color: config-dark.$defaultColor;
}

Mais cette manière de faire va vite poser des limites, je vais donc organiser le code d'une autre manière.

Le pattern de theme

Au lieu de développer directement le composant dans un fichier, je vais le mettre dans un mixin.

./src/components/_button.scss
@mixin my-button-component($theme) {
    $colors: map-get($theme, 'colors');

    .button {
        background-color: map-get($colors, 'backgroundColor');
        color: map-get($colors, 'defaultColor');
    }
}

Ce mixin ne va demander qu'un seul argument: le thème avec toutes les variables dont le composant va avoir besoin.

Après, je modifie le fichier _config.scss pour y ajouter mes deux thèmes sous la forme de deux variables.

./src/_config.scss
$theme: (
    'colors': (
        'backgroundColor': white,
        'defaultColor': black,
    ),
);

$theme-dark: (
    'colors': (
        'backgroundColor': black,
        'defaultColor': white,
    ),
);

Je me permets de mettre les deux thèmes dans le même fichier, mais ce n'est pas obligatoire.

Enfin, je rajoute un fichier ./src/_theme.scss qui va 'instancier' tous les composants avec le thème.

./src/_theme.scss
@use 'components/button';

@mixin my-theme($theme) {
    @include button.my-button-component($theme);
}

Je peux ainsi modifier le fichier d'entrée comme ceci:

./style.scss
@use 'src/config';
@use 'src/theme';

@include theme.my-theme(config.$theme);
.dark {
    @include theme.my-theme(config.$theme-dark);
}

Tous les composants appliqueront automatiquement le nouveau thème. Toutes les variables seront appliquées à tous les composants.

Le résultat est le même que pour la solution précedente.