Du code Sass facilement maintenable ?

Du code Sass facilement maintenable ?

Les préprocesseurs css sont maintenant bien installés dans le paysage technique du développement Front, si bien qu’il est aujourd’hui impensable d’utiliser du css pur sur un projet, sans passer par sass ou less pour ne citer qu’eux. Cependant malgré le fait qu’on les utilise tous les jours, on néglige parfois toute l’étendue de leur pouvoir, le but ici est de voir quelques bonnes pratiques permettant de produire un code plus facilement maintenable.

Architecture

L’architecture CSS n’est pas chose aisée, surtout lorsque l’on souhaite mettre en place une architecture cohérente et maintenable sur le long terme.

C’est là qu’intervient une feature très intéressante de Sass à savoir l’@import. Cela permet de séparer son code en autant de fichiers et dossiers que nécessaire au bon développement du projet, et de tout compiler en un seul fichier destiné à la production.

La méthodologie la plus répandue et qui semble être la plus efficace est appelée 7-1 Pattern : 7 dossiers, 1 fichier. Ici on décompose le style en 7 dossiers différents et un fichier à la racine qui va tous les importer afin d’être compilé en un fichier Css.

Voici concrètement comment cela se présente, on a donc 7 dossiers (dans cet ordre) :
– Abstracts/
– Base/
– Vendors/
– Layouts/
– Components/
– Pages/
– Themes/
Et enfin main.scss

Notre dossier abstracts va contenir tous les outils sass dont nous avons besoin (variables, mixins, fonctions, placeholders…).

Dans le dossier base on retrouve notre reset et les règles typographiques. On peut également y trouver un fichier generic appliquant du style sur des éléments html globaux.

Le dossier vendor va quant à lui contenir tout le style venant des librairies externes et autres frameworks (swiper, select2, bootstrap…)

Dans layouts sont regroupés les différentes parties du site ou de l’application (header, footer, navigation, grid, forms…)

Pour le dossier components c’est une peu comme layouts mais à une échelle plus petite, c’est ici qu’on aura les composants du projet (slider, social-share, hero, buttons, dropdown…)

Pages va contenir tout le style spécifique à certaines pages.

Le dossier themes va contenir les styles relatifs aux différents thèmes (author, admin, super-admin, reviewer…). À noter que cela est très spécifique au contexte du projet il est possible que ce dossier ne soit pas nécessaire.
De plus nous allons voir par la suite qu’il est aussi possible de gérer le thème directement depuis le composant par exemple.

Il faut garder à l’esprit que les fichiers et dossiers seront importés les uns après les autres suivant leur ordre de déclaration. C’est la raison pour laquelle l’ordre de d’import à son importance, il permet de limiter les conflits lors de la compilation et d’éviter les surcharges css.

Une fois que l’on a tous nos dossiers et nos fichiers il nous reste plus qu’à importer le tout dans mains.scss qui va donc ressembler à ça :

@import
  'abstracts/variables',
  'abstracts/functions',
  'abstracts/mixins',
  'abstracts/placeholders';
 
@import
  'base/reset',
  'base/typography';
 
@import
  'vendors/bootstrap',
  'vendors/jquery-ui';
 
 
@import
  'layout/navigation',
  'layout/grid',
  'layout/header',
  'layout/footer',
  'layout/sidebar',
  'layout/forms';
 
@import
  'components/buttons',
  'components/carousel',
  'components/cover',
  'components/dropdown';
 
@import
  'pages/home',
  'pages/contact';
 
@import
  'themes/theme',
  'themes/admin';

On peut noter plusieurs avantages qui découlent de cette organisation :
– Onboarding plus limpide, les nouveaux arrivants sur le projet mettront peu de temps avant de mettre la main sur les fichiers dont ils ont besoin
– Les phases debug deviennent moins complexes dès lors que l’organisation est cohérente
– Il est très simple de faire évoluer l’application ou le site par exemple si de nouveaux composants doivent être créer par exemple.

Esperluette ?

C’est je pense l’une des fonctionnalités la plus intéressante de Sass. Je ne vais pas trop m’attarder sur les usages de base de l’& car si vous lisez ceci vous savez probablement à quoi il sert et comment l’utiliser. Il faut juste garder en tête qu’il prend comme valeur le sélecteur parent.
Cependant lorsqu’on utilise BEM (Block Element Modifier), l’esperluette prend une autre dimension et s’avère être un gain de temps énorme.

Prenons l’exemple d’un composant très basique mais qui peut se retrouver sous plusieurs états différents :

Nous avons ici un thème light et un thème dark. En respectant BEM nous allons donc avoir le code html suivant:

  
  <div class="component component--light">
    <div class="component__title">
      <h2>...</h2>
    </div>
    <div class="component__content">
      <p>...</p>
    </div>
    <div class="component__footer">
      <a href="" class="component__button">...</a>
    </div>
  </div>

  <div class="component component--dark">
    <div class="component__title">
      <h2>...</h2>
    </div>
    <div class="component__content">
      <p>...</p>
    </div>
    <div class="component__footer">
      <a href="" class="component__button">...</a>
    </div>
  </div>
</div>

Rien de très particulier jusque-là, ce qui va nous donner le code scss que voici :

.component {  
  
  &--dark {
    
    .component__title,
    .component__content {}
    
    .component__button {}
  }
  
  &--light {
    
    .component__title,
    .component__content {}
    
    .component__button {}
  }
  
  &__title {}
  
  &__content {}
  
  &__footer {}
  
  &__button {}
}

On voit bien ici nos composants avec les variations de styles imposées par les thèmes et en dessous les styles qui ne changent pas quel que soit le thème. On peut si l’on souhaite, placer les styles par défaut au-dessus pour plus de lisibilité. Cependant si je dois modifier le style du titre, je serai potentiellement amené à faire une modification à 3 endroits différents dans le fichier. Imaginons alors si nous avions plus que 2 modifiers et si nous avions des composants plus complexes à gérer. Cela deviendrait vite compliqué à maintenir.

Souvenez-vous que & prend comme valeur son sélecteur parent… Voici donc ce qu’on peut faire pour améliorer le code :

.component {  
  
  &--dark {}
  
  &--light {}
  
  &__title {
    
    .component--dark & {}
    
    .component--light & {}
  }
  
  &__content {
    
    .component--dark & {}
    
    .component--light & {}
  }
  
  &__footer {}
  
  &__button {
    
    .component--light & {}
    
    .component--dark & {}
  }
}

Voilà qui est mieux, maintenant si je dois modifier title, toutes les modifications se feront au sein de son sélecteur. Bien que le modifier soit appliqué sur le composant parent, grâce à l’esperluette je peux désormais gérer les variations de styles résultantes des classes parentes.

Maintenant on se rend compte que si dans mon composant j’ai 10 éléments, dont le style change en fonction du thème, je vais devoir écrire le sélecteur parent au moins 20 fois… Il n’y a pas de honte à être fainéant, je peux donc compter sur les variables pour réduire le nombre de modifications que j’aurai à faire dans le cas ou .component change de nom.

.component {
  $component: &;
  
  &--dark {}
  
  &--light {}
  
  &__title {
    
    #{$component}--dark & {}
    
    #{$component}--light & {}
  }
  
  &__content {
    
    #{$component}--dark & {}
    
    #{$component}--light & {}
  }
  
  &__footer {}
  
  &__button {
    
    #{$component}--light & {}
    
    #{$component}--dark & {}
  }
}

On peut stocker l’& dans une variable et l’intérêt de déclarer cette variable dans le composant est de pouvoir réutiliser ce même nom de variable dans un autre composant. Maintenant il nous reste plus qu’à mettre aussi le nom du thème dans une variable :

.component {
  $component: &;
  $darkTheme: #{$component}--dark;
  $lightTheme: #{$component}--light;
  
  &--dark {}
  
  &--light {}
  
  &__title {
    
    #{$darkTheme} & {}
    
    #{$lightTheme} & {}
  }
  
  &__content {
    
    #{$darkTheme} & {}
    
    #{$lightTheme} & {}
  }
  
  &__footer {}
  
  &__button {
    
    #{$lightTheme} & {}
    
    #{$darkTheme} & {}
  }
}

Il est intéressant de voir que tout ce que l’on vient de produire repose en grande partie juste sur l’utilisation de &
Les avantages de cette technique sont :
– Gain de temps, on écrit très peu de fois le nom des sélecteurs en cas de modifications ou d’ajout d’enfants cela devient plus rapide
– Clarté, il est très facile de voir tout le style appliqué à un élément cela rend le code plus lisible
– Scalabilité, on peut descendre encore de 8 niveaux ça marche encore (même s’il est conseillé de ne pas descendre en dessous de 3 niveaux)
– Maintenabilité, on évite les surchages css, les modifications de styles engendre moins d’erreurs de type (image gif si je touche je ne sais pas ce que ça fait)

Mixins ou Placeholders

Une mixin est une directive qui permet de définir plusieurs règles en fonction des arguments qu’elle reçoit, un peu comme une fonction mais au lieu de retourner une valeur, elle renvoie du contenu CSS.

Les placeholders sont un peu particuliers. Ils s’utilisent comme des sélecteurs de classes pour permettre de définir du style et sont appelés par @extend. Ici @extend va simplement recopier le contenu du placeholder au sein du selecteur où il sera appelé.

Voici un petit exemple pour mieux comprendre.

@mixin button {
  text-decoration: none;
  border: solid 1px #000;
}

.cta {
  @include button;
}

.link {
  @include button;
}

//code compilé

.cta {
  text-decoration: none;
  border: solid 1px #000;
}

.link {
  text-decoration: none;
  border: solid 1px #000;
}

La mixin va recopier le code autant de fois qu’elle sera appelée. C’est pratique lorsqu’on veut réutiliser du style plusieurs fois dans le fichier sans avoir à recourir à des noms de classes non sémantiques par exemple.

%button {
  text-decoration: none;
  border: solid 1px #000;
}

.cta {
  @extend %button;
}

.link {
  @extend %button;
}

//code compilé

.cta, .link {
  text-decoration: none;
  border: solid 1px #000;
}

Sass va aller chercher le contenu du placeholder %button pour l’appliquer à .cta et .link.
Il faut savoir qu’on ne peut pas passer de variables dans un placeholder il est donc impossible de générer du css spécifique au contexte.

Pour savoir dans quel cas utiliser l’un ou l’autre je dirai qu’étant donné que Sass recopie le rendu de la mixin à chaque fois qu’elle est appelée, il est préférable de privilégier les placeholders car la compilation s’effectue par groupage de sélecteurs sans répéter le style. Par contre, lorsque l’on veut utiliser les mêmes propriétés mais avec des valeurs différentes, il est préférable d’utiliser mixin.

 

Le CSS c bô

Voici quelques tricks parmi tant d’autres mais ils ont selon moi une grande utilité, car maintenir du code css propre est très compliqué et encore plus sur des projets de grande envergure. Bien évidemment le contexte du projet va grandement définir les choix techniques que l’on va adopter, par exemple avec une technologie comme vue.js, où le style est directement au sein du fichier du composant, certaines de ces techniques ne seront peut-être pas utiles. Il est donc évident que cela ne résolve pas toutes les difficultés rencontrées lors du développement mais peut contribuer à améliorer la qualité du code produit.