Définir son style CSS avec CAP

Il existe de multiples façons de découper son style en de multiples composants graphiques. Je vous invite à lire mes précédents articles sur Atomic Design si vous souhaitez connaître une technique qui se base sur un assemblage de composants.

En revanche, dans Atomic Design, rien ne vous indique comment définir concrètement vos composants, comment écrire ses classes, comment éviter de créer des conflits entre vos atomes, molécules et organismes.

Pour répondre à certaines problématiques de représentation du style, nommer des classes d’une façon particulière permet de ne pas coupler le sens de son composant graphique au sens des tags HTML. Vous pourrez trouver des conventions de nommage associées à une réelle méthodologie d’organisation avec OOCSS, SUIT CSS et sans doute un des plus populaires aujourd’hui : BEM.

Je vous propose de découvrir CAP, pour Component Alternative Part, une autre façon de représenter son style, fortement inspirée de BEM et avec plus de respect pour les usages communs en CSS.

Inspiré par BEM, simple et populaire

Avec le temps, j’ai moi aussi retenu BEM pour son principe très simple, c’est-à-dire :

  • B : Représente un Block ;
  • E : Se définit comme une sous partie d’un Block, c’est un Element ;
  • M : Permet de gérer les changements d'apparences ou les états d’un block ou d’un élément. C’est un Modifier.

Un block se définit par une classe unique dans le style alphanumérique et séparée par des tirets -. Rien n’est cité sur l’utilisation ou non de majuscules, ainsi il est possible d’écrire un block sous la forme my-block ou My-block.

L’element est la concaténation du nom d’un block et du nom de l’élément séparé de deux underscores __, il peut donc s’écrire my-block__my-element.

Le modifier est la concaténation des noms d'un block et du modifier séparés par deux tirets --. Il peut donc s’écrire my-block--my-modifier.

Ainsi, en SCSS, nous pouvons écrire un exemple du type :

.my-block {
  /* Block code */

  &__my-element {
    /* Element code */
  }

  &--my-modifier {
    /* Modifier code */
  }
}

Cependant, l’utilisation de l’underscore _ n’est pas courante dans mon utilisation de CSS, il suffit de voir les différents frameworks CSS (Bootstrap, Tailwind CSS, Bulma …) pour s’en convaincre.

De plus, l’utilisation de noms de classes selon la syntaxe BEM peut vite devenir verbeuse :

<div class="my-block my-block--my-modifier">
  Block
  <div class="my-block__my-element">Element</div>
</div>

Pour cette raison, après avoir croisé plusieurs utilisations de BEM, je suis tombé sur un article dont je n’ai malheureusement plus la source et qui propose de simplifier les modifiers en utilisant seulement le nom du modifier préfixé d’un tiret -. Ici, cela donne -my-modifier, soit le code suivant :

.my-block {
  /* Block code */

  &__my-element {
    /* Element code */
  }

  &.-my-modifier {
    /* Modifier code */
  }
}

Même si j’étais perplexe au début, il est important de noter qu’un modifier est toujours associé soit à un block, soit à un element, ce qui rend finalement l’utilisation de cet ajout très élégant et plus concis par rapport à ce que prévoit BEM initialement :

<div class="my-block -my-modifier">
  Block
  <div class="my-block__my-element">Element</div>
</div>

Il ne reste donc plus que l'utilisation de l’underscore qui me pose problème, et pas seulement à moi, vous pouvez voir que l’outil d’analyse statique StyleLint n’aime pas non plus ce caractère de séparation puisqu’il autorise les caractères alphanumériques ainsi que les tirets -.

Arrivée de Component Alternative Part (CAP)

En m’inspirant du travail de BEM, j’utilise depuis plusieurs années une syntaxe avec ses avantages, incluant le système de modifier préfixés par un tiret seul - et avec des -- à la place des underscores __. Ainsi cette syntaxe, bien que inspirée, ne peut pas être confondue avec BEM puisque dans ce cas, la représentation d’un element entre en conflit avec la représentation d’un modifier.

CAP, pour Component / Alternative / Part fonctionne ainsi :

  • C : Représente simplement un composant (analogue au B de BEM)
  • A : Désigne une alternative de composant, un état ou de sous-partie de composant (analogue au M de BEM)
  • P : Est une sous-partie d’un composant (analogue au E de BEM)

Ainsi, un component est défini par des caractères alphanumériques minuscules et séparés par des tirets -, il ne peut pas commencer par un -.

La part est la concaténation d’un component et du nom de la part séparés par des --.

Pour une sous-partie d’une part, rien ne vous oblige à appliquer à nouveau la même règle, ainsi il est possible d’écrire my-component--my-part--my-subpart ou my-component--my-part-my-subpart, l’important est surtout de cloisonner le style par rapport au nom du component.

L’alternative se définit par le nom de l’alternative, précédé par un -.

Si on reprend les exemples vus dans la section précédente avec BEM, dans CAP, cela donne (adapté avec les termes de CAP) :

.component {
  /* Component code */

  &.-alternative {
    /* Alternative code */
  }

  &--part {
    /* Part code */
  }
}

CAP prévoit aussi la notation préfixée. Cette notation arrive en amont du nom du composant, ce qui donne :

.prefix-component {
  /* Component code */

  &.-alternative {
    /* Alternative code */
  }

  &--part {
    /* Part code */
  }
}

Ce qui donne, lorsqu’on l’utilise avec HTML :

<div class="prefix-component -alternative">
  Component
  <div class="prefix-component--part">Part</div>
</div>

Pour avoir une idée d’un composant graphique fait en utilisant CAP, je vous propose de suivre ce CodePen.

Quoi d’autre ?

La convention de nommage ainsi que la méthode de fabrication de composants que je décris ici me permet aujourd’hui d’éviter de nombreux effets de bords.

Il ne faut cependant pas oublier pourquoi vous faîtes vos composants. Voyez CAP comme un outil que vous pourrez utiliser pour vous aider à les ranger. Par ailleurs, l’approche ne suffira pas si vous ne choisissez pas des noms pertinents ou une stratégie efficace pour ranger vos composants.

Aujourd’hui, j’utilise cette convention au quotidien et, couplé à Atomic Design, elle m’aide à cloisonner ainsi que découpler mes composants. Il devient ainsi très facile de maintenir, de faire évoluer et d’améliorer mon style graphique.