Maintenabilité du code HTML / CSS : entre automatisation et guide de style

En ce moment, chez Capgemini, j’ai la chance de travailler sur un projet agile où la qualité est le maître mot grâce à une volonté du client de prime abord, et bien sûr, de l’équipe de réalisation.

La qualité de l’intégration HTML / CSS est vérifiée à 2 niveaux :

  • une agence qui contrôle l’accessibilité au niveau AA du RGAA en vue d’un audit final ;
  • une agence qui fait des revues de notre code pour en assurer la qualité et la maintenabilité.

Depuis que je suis intégratrice, je crois que c’est la première « vraie » fois où je suis challengée sur le code que je produis, où mon code est revu par une autre personne. Ça peut paraître fou mais il y a quand même très souvent un seul intégrateur ou une seule intégratrice sur un projet (selon sa taille).

Sur ce projet, c’est donc carrément une entreprise externe qui fait les revues de code d’intégration : Alsacréations, et plus précisément Jennifer Noesser dans un premier temps. Que rêver de mieux pour progresser ?

On ajoute à cela un défi : l’intégration avec mise en place d’un guide de style, une première pour l’équipe.

Les premiers retours qui agacent : lancer des tâches automatisées pour y remédier

Lorsqu’on a eu les premiers retours d’Alsacréations, il y avait beaucoup de choses qui revenaient sans arrêt sur la CSS parce que c’étaient les « petits détails qui font la différence » et qu’il était difficile d’y penser à chaque fois ou de ne pas en rater un seul. C’est agaçant pour le relecteur ou la relectrice ainsi que pour la personne qui reçoit ces retours et doit les corriger.

L’indentation : EditorConfig pour tous

Au début du projet, l’équipe s’était mise d’accord sur l’indentation :

  • 2 espaces pour les fichiers HTML / PHP / JS car c’est la norme côté Drupal ;
  • 4 espaces pour les fichiers SCSS car on trouve que c’est plus facilement lisible (et que Drupal n’a rien à voir là dedans).

Malgré toute la bonne volonté du monde, la configuration de nos outils n’était pas suffisante. Parfois, certains fichiers mélangeaient les espaces et les tabulations. On voyait qu’il y avait un problème en regardant nos fichiers dans Gitlab car tout semblait déstructuré.

Jennifer nous a alors conseillé un outil assez génial pour que l’indentation ne soit plus un calvaire sur les projets : EditorConfig.

EditorConfig, c’est un petit fichier « .editorconfig » qu’on ajoute à la racine du projet et dans lequel on définit le mode d’indentation par défaut pour le projet et, si besoin, des modes d’indentation spécifiques pour certains formats de fichiers.

Pour certains éditeurs de code (comme Sublime Text, Brackets, PhpStorm, etc.), il faut installer une extension afin que la configuration soit prise en compte. Ensuite, dès qu’on ouvre un fichier du projet ou qu’on en crée un nouveau, il se met directement dans le bon format d’indentation.

Exemple de configuration :

root = true

[*]
end_of_line = lf
insert_final_newline = true
charset = utf-8
indent_style = space
indent_size = 2

[*.{scss,sass}]
indent_size = 4

Sass-lint à la rescousse : les bonnes pratiques d’écriture de code CSS / Sass

Les « petits détails qui font la différence » ont leur importance car ils permettent de rendre le code plus propre, plus facile à lire et donc, plus maintenable. On peut se dire qu’Alsacréations chipote sur ce coup-là mais je vous assure qu’après avoir mis en place ces bonnes pratiques, le code CSS est beaucoup plus lisible et on s’y retrouve donc mieux. Quelques exemples :

  • mettre une espace après chaque « : » qui sépare une propriété CSS de sa valeur ;
  • mettre une espace avant chaque ouverture d’accolade « { » ;
  • ranger les propriétés CSS dans un ordre défini (selon celui de SMACSS, par exemple : d’abord les propriétés de boîte, puis de bordures, puis de fond, puis de texte, puis les autres) ;
  • éviter les imbrications trop complexes avec trop de niveaux : les sélecteurs CSS seront moins longs, les performances s’en porteront mieux (même si ce n’est pas le plus impactant) et la maintenance du code HTML et CSS sera facilitée en évitant les classes trop génériques (risque de régressions et de conflits de style où !important deviendrait nécessaire).

Tout ça pour dire, finalement, qu’on ne codait pas très proprement. La maintenance serait donc plus complexe pour nous dans le futur ou pour un nouveau ou une nouvelle venu·e sur le projet.

On corrigeait ces problèmes mais on ne voyait pas tout. Au bout de deux ou trois retours identiques, je me suis dit qu’il devait y avoir un moyen d’automatiser ces tâches ou, en tout cas, d’en automatiser les tests pour réussir à les corriger nous-mêmes avant d’envoyer notre code en relecture. C’est le principe des « linter ».

On a donc installé Sass-lint sur le projet, via Gulp, et défini les règles à appliquer dans le fichier YAML (exemple de fichier sass-lint.yml) :

  • les espacements ;
  • les unités de mesure pour certaines propriétés CSS :
    • pas d’unité pour line-height (référence) ;
    • margin et padding en unités rem ;
    • que des unités relatives pour font-size afin de ne pas gêner les utilisateurs qui souhaitent zoomer le texte ;
    • etc.
  • le niveau d’imbrication maximal ;
  • la propriété border qui ne doit pas avoir pour valeur none uniquement (c’est la valeur zéro qui la réinitialise vraiment) ;
  • l’indentation des fichiers Sass (ça remonte une alerte si l’indentation n’est pas bonne ; EditorConfig ne gère pas ça) ;
  • l’ordre des propriétés CSS selon SMACSS ;
  • pas de !important ;
  • etc.
Capture d'écran d'un morceau de code contenant des avertissements de Sass-Lint dans la console
Illustration – Exemple d’avertissements de Sass Lint dans la console

Même si cela a été pénible de faire toutes les corrections d’un coup, ensuite, ça facilite grandement la tâche de relecture et ça évite d’avoir des doublons de propriétés CSS, par exemple. Maintenant, on n’a plus le droit de commiter du code si on a un seul avertissement de Sass-lint dans la console.

À l’arrivée sur le projet, on peut avoir un peu de mal à tout faire correctement mais la console est un guide. Très rapidement, on finit par connaître les règles par cœur, on crée des automatismes et, par défaut, il n’y a donc généralement plus beaucoup d’avertissements de Sass-lint.

Parfois, on a quand même besoin de déroger à certaines règles. Dans ces cas-là, on doit expliquer pourquoi on y déroge. Ensuite, on désactive Sass-lint pour l’élément concerné.

/* Désactiver une règle pour un fichier entier : */
// sass-lint:disable no-important 
.link {
	color: #FFFFFF !important; // Force color for hover and focus too 
}

/* Désactiver une règle pour une seule ligne */
.link {
	// Force color for hover and focus too
	color: #FFFFFF !important; // sass-lint:disable-line no-important 
}

/* Désactiver une règle dans un bloc (et tous les blocs inclus) */
.link {  
	// sass-lint:disable-block no-important
	color: #FFFFFF !important; // Force color for hover and focus too 
}

Allons plus loin : auto-prefixer pour se simplifier encore un peu plus la vie

J’ai beau adorer le service que fournit Can I Use, je préfère quand les choses automatisables se font toutes seules. Savoir si je dois continuer à utiliser la version préfixée pour Webkit, pour Mozilla, pour Microsoft, pour Opera est, encore une fois, un calvaire. On préfèrera donc conserver un pan de mémoire pour quelque chose de plus utile que ça.

Comme on utilise Gulp pour la compilation de notre code Sass sur le projet, je me suis mise en quête de l’installation du module gulp-autoprefixer. On peut définir quelle est la version minimale supportée pour chaque navigateur et ça nous facilite grandement la vie !

Dans Sass-lint, on interdit alors l’usage des préfixes.

L’intégration en mode « styleguide », c’est pas si simple

Notre projet avait une version 1 avec un guide de style (styleguide, en anglais) existant à prendre comme base pour construire une version 2. Ce mode de fonctionnement était donc imposé au départ et on ne savait pas vraiment comment il fonctionnait ni comment l’utiliser. Le guide de style était déjà construit avec SC5, un générateur de guide de style basé sur KSS. Au début, on y est allé un peu à tâtons avec des explications d’Alsacréations sur le fonctionnement technique de KSS et la v1 déjà construite. On n’avait juste pas pensé à demander des précisions sur ce que ça implique en terme de conception. Et pourtant, ça change tout !

On a commencé par tenter une réorganisation des fichiers car on avait environ cinq gros fichiers SCSS dans le projet v1 avec tout le code HTML pour construire les composants du guide de style dans ces fichiers.

Les User Stories ont commencé à arriver et on s’est vite rendu compte que la v2 n’aurait rien à voir avec la v1. Petit à petit, on déconstruisait donc les styles de la v1.

Jennifer nous expliquait 2–3 choses sur le nommage des classes pour que ce soit plus maintenable, plus performant, avec moins d’imbrications :

  • une classe déjà spécifique n’a pas besoin d’être imbriquée dans un élément parent spécifique. Exemple : .article-title n’a pas besoin d’être imbriqué dans .article ;
  • on devrait utiliser plus de classes spécifiques pour éviter trop d’imbrications et les sélecteurs CSS trop longs. Quand on imbrique, on ne se rend pas forcément compte qu’on est en train de créer un sélecteur à rallonge comme ça, par exemple : .top-news .content .content-text .top-title ;
  • etc.

On ne comprenait pas vraiment l’importance de tout ça. On fonctionnait avec une classe parente et tous les enfants imbriqués en SCSS comme en HTML. On veillait à ce que la structure des blocs se ressemblant soit cohérente à base de .content-text et .content-image imbriqués dans la classe parente du composant. Ça avait une certaine logique.

Notre arborescence de fichiers n’était pas optimale ; on se demandait toujours dans quel dossier il fallait ranger tel ou tel composant, dans « modules » ou dans « master » ?

— « Master », c’est le dossier où on range les composants qu’on utilise à plusieurs endroits.
— Oui, mais le principe du guide de style est de faire des composants qu’on peut réutiliser n’importe où.

Pour finir, on a voulu mettre notre composant « paragraphe » dans une autre page qu’un article et on ne pouvait pas. Il dépendait d’une classe parente .article.

.article {
	// CSS properties here
	
	.content-text {
		// CSS properties here
		
		// WYSIWYG styles
		p {
			// CSS properties here
		}
		
		ul {
			// CSS properties here
		}
	}
	
	.content-image {
		// CSS properties here
	}
}

Là, on a compris où était le problème dans notre mode de fonctionnement. On a tout cassé pour repartir sur de meilleures bases. Faisons le point sur les solutions mises en place.

Une architecture de fichiers où on s’y retrouve

L’architecture de fichiers en place nous perdait, depuis le début du projet. Je me suis donc un peu renseignée et je suis tombée sur l’excellent site Sass Guidelines où est proposée une architecture qui m’a semblée logique et correspondant assez bien au modèle de guide de style :

  • abstracts/ : les variables, etc. ;
  • base/ : la grille de mise en page, Normalize CSS, les règles de typographie sur les balises standards (body, hn…), etc. ;
  • components/ : les composants à réutiliser à volonté partout dans le site ;
  • layout/ : les éléments du gabarit (en-tête, pied de page, fil d’ariane, formulaires, etc.) ;
  • pages/ : les styles qui concernent les pages (hors composant) – par exemple, la gestion des marges sur les conteneurs de chaque composant pour une page en particulier, ou un fond de page, etc. ;
  • themes/ : si on gère différents thèmes dans le site ;
  • vendors/ : les librairies externes (associées à une librairie JS par exemple).

Depuis qu’on a mis ça en place, on ne se perd plus dans nos fichiers, on sait où les ranger et où les retrouver. En revanche, on se rend vite compte qu’il peut être utile de créer des sous-dossiers dans « components » si on a plusieurs composants associés à une même thématique.

Le nommage des classes ou la construction d’un composant réutilisable

Chaque élément doit être un composant qu’on peut réutiliser n’importe où dans le site peu importe la classe parente qu’a la page sur laquelle on se trouve.

La première étape a été de réécrire notre composant « paragraphe » qui dépendait de la classe parente .article. Alors, j’ai repris les explications de Jennifer et avec un œil plus avisé, j’ai mieux compris.

J’ai trouvé un préfixe pour mon composant qui allait préfixer toutes mes classes CSS pour celui-ci : .paragraph (facile pour celui-là qui n’est composé que d’un mot !). Dans mon bloc « paragraphe », j’ai une image et du texte :

  • .paragraph-text
  • .paragraph-image

En revanche, le contenu vient d’une contribution via un éditeur WYSIWYG ; je ne peux donc pas mettre de classes sur toutes les balises qui le composeront (comme on pourrait le faire avec BEM, par exemple). J’imbrique alors le style de mes balises p et ul dans .paragraph-text. Tout le reste est au même niveau. Ne plus imbriquer ces classes dans la classe .article permet, entre autres, de réduire la spécificité des styles et la longueur des sélecteurs CSS.

.paragraph-text {
	// CSS properties here
	
	// WYSIWYG styles
	p {
		// CSS properties here
	}
	
	ul {
		// CSS properties here
	}
}

.paragraph-image {
	// CSS properties here
}

Parfois, il y a des composants plus complexes avec des noms à rallonge (plus d’un mot) qu’il est difficile de rétrécir (comme « store locator » par exemple). Dans ce cas, on a des classes qui peuvent devenir vraiment très longues ; ce n’est pas optimal. Mais, on sait à quel élément on a affaire, on sait sur quel périmètre on intervient lorsqu’on fait une modification. On évite donc les régressions.

Si je reviens sur le projet dans six mois ou si une nouvelle personne arrive, on peut comprendre comment est construit un composant. L’affichage du guide de style y sera aussi pour beaucoup car il permet d’avoir le rendu d’un composant avec son code HTML et CSS en parallèle (exemple de rendu).

Il peut être difficile d’aborder une nouvelle maquette avec de nouveaux composants. Dans ces cas-là, rien de tel qu’une bonne analyse de maquettes. On les imprime, on les accroche sur un tableau et on se pose 15 minutes pour :

  • trouver un préfixe à nos composants ;
  • définir les zones :
    • où commence et où se termine le composant ;
    • à quel moment on en crée un nouveau ;
    • à quel moment on réutilise un composant existant (faut-il lui ajouter un élément ou le réutiliser tel quel ?).
  • identifier ce qui est commun.

Jennifer parle d’ailleurs très bien de ce sujet dans son article Un guide qui a du style !

SC5 et KSS : le markup HTML dans les fichiers Sass

Un guide de style est pratique pour toutes les personnes intervenants sur le projet (designer, intégrateur·trice, développeur·euse…). Il permet d’avoir une vue d’ensemble des réalisations, de savoir construire seul·e une nouvelle page avec des composants existants.

On peut faire ce guide à la main ou grâce à des générateurs automatisés. Sur le projet qui nous intéresse, on a travaillé avec SC5, générateur basé sur KSS.

KSS fait mettre le markup HTML directement dans les fichiers Sass. Grâce à SC5, on peut se contenter de construire la documentation (titre, explication) de KSS dans l’en-tête du fichier pour finalement mettre le code HTML dans des fichiers externes avec la bonne extension « .HTML ». De cette façon, le code Sass est documenté et reste lisible. Le code HTML est, quant à lui, facile à écrire. A noter qu’il est possible, grâce à SC5, d’inclure un composant dans un autre grâce à une balise <sg-insert>3.2</sg-insert>, à la manière d’une fonction include en PHP.

Dans l’exemple ci-dessous, le markup est externalisé dans un fichier .html et, grâce à sg-wrapper: et à la balise <sg-wrapper-content/> qui appelle le fichier de markup, on peut ajouter des éléments hors composant pour ajuster la mise en page dans le guide de style (voir la documentation). Ainsi, on peut montrer le composant en vue desktop et en vue mobile, dans un conteneur à 320px de large.

// Nom du composant
//
// Description du composant
//
// markup: ../markup/3.2-paragraph.html
//
// sg-wrapper:
// <p>Desktop version</p>
// <div class="desktop-view">
//   <sg-wrapper-content/>
// </div>
// <p>Mobile version</p>
// <div class="mobile-view">
//   <sg-wrapper-content/>
// </div>
//
// Styleguide 3.2

.paragraph-text {
	// CSS properties here
	
	// WYSIWYG styles
	p {
		// CSS properties here
	}
	
	ul {
		// CSS properties here
	}
}

.paragraph-image {
	// CSS properties here
}

On peut également créer autant de fichiers de markup qu’il y a de déclinaisons possibles pour les composants ou les compositions (pages). On crée alors des sous-parties dans notre composant (3.2.1, 3.2.2, etc.).

En conclusion, le mot « maintenabilité » fait désormais sens

En trois mois de relecture par Jennifer, alors chez Alsacréations, j’ai appris plus sur la qualité du code qu’en cinq ans d’expérience. Désormais, je comprends bien mieux la définition des mots « maintenabilité » ou « code propre ».

Si vous avez la chance d’avoir une personne qui peut relire votre code, n’hésitez pas à la solliciter car on a tous beaucoup à apprendre, peu importe le nombre d’années d’expérience qu’on a derrière soi.

Ces relectures ont permis de soulever d’importants problèmes de maintenabilité de notre code et de nous remettre en question. On a trouvé des solutions pour nous faciliter la vie ; en mettant en place l’automatisation de tests de qualité du code, cela a fini par créer des automatismes. Et, surtout, on a découvert que l’intégration sous forme de guide de style est, certes complexe, mais nécessaire.

Avec un peu de recul, je pense que ça doit être plus facile avec une méthodologie de nommage de classes comme BEM ou OOCSS par exemple. La prochaine étape dans cette évolution est de regarder de ce côté-là pour essayer de faciliter et de normaliser un peu plus nos intégrations entre les projets.

5 commentaires sur cet article

  1. David Dias, le lundi 4 décembre 2017 à 09:41

    Très bon article qui pose certaines bases pour une bonne maintenabilité du code mais je pense qu’il aurait été intéressant de pousser un peu plus loin et de choisir différents outils plus modernes et efficaces.

    Stylelint est selon moi beaucoup plus performant et répandu que Sass-lint de nos jours.

    Prettier est aussi excellent pour justement permettre une maintenabilité acrue et évident des erreurs lors de pull requests.

    BEM est vraiment une très bonne méthodologie à recommander même aux débutants pour les forcer à bien organiser leur composants.

    Sass est effectivement un des meilleurs pre-processeurs CSS et permet quand coupler à BEM une organisation efficace (voir utilisation de l’ampersand avec BEM).

    On pourrait aussi citer, comme alternative à SC5 (uniquement pour Sass) http://sassdoc.com créé par Kitty Giraudel et qui permet d’avoir une documentation des fichiers Sass.

    Merci encore pour ce partage d’expérience !

  2. Copin Grégory, le lundi 4 décembre 2017 à 09:59

    Chouette partage. Par curiosité et aussi parce qu’il y a plein de bonnes choses à prendre, je ne peux que vous conseiller de vous renseigner sur ITCSS, une philosphie développée par Harry Roberts. J’ai fait une traduction d’une de ses conférences ici (https://medium.com/dev-notes/just-do-itcss-1cb8a0c441d8) si vous le souhaitez

  3. Nico, le lundi 4 décembre 2017 à 12:57

    Merci pour ce billet. J’avoue que j’avais lâché l’affaire « génération de styleguide » depuis la CSS sur mes projets (c’est ça d’avoir un graphiste qui le fait trop bien !), mais je vais jeter un œil à ce que tu mentionnes, c’est qqch que j’aimerais avoir à terme, en mode living styleguide.

    Après, sur les règles de maintenabilité, perso, le nesting doit être l’exception et absolument pas la règle. BEM peut être une bonne aide.

    Un point trop souvent oublié : selon moi, dans l’absolu, l’organisation de la CSS doit permettre de comprendre certaines variables du projet, point abordé ici : https://rocssti.net/news-rocssti#organisation ;)

  4. Cyrille Jesmo Drazik, le lundi 4 décembre 2017 à 13:43

    Merci pour l’article. Comme déjà soulevé dans les commentaires précédents, pour le linting je conseille plutôt de partir sur StyleLint. Il s’est imposé dans l’écosystème, est très bien maintenu et il est très modulaire, ce qui permet d’utiliser des plugins (comme stylelint-scss, si tu fais du SCSS) afin qu’il colle au plus près du besoin.

    Enfin, pour tout ce qui est style de code (2 ou 4 espaces, un espace avant les accolades, un espace après les « : », etc), je suggère fortement de désactiver toutes les règles en rapport avec ça dans le linter, pour plutôt utiliser Prettier ou Perfectionist, par exemple.

    Le Styleguide nécessite une grande rigueur, mais cela vaut largement la peine. Je conseille de commencer à l’utiliser sur un « petit » projet. Dans ma boîte, j’ai tenté de l’introduire sur un projet trop gros, un manque de rigueur s’est fait ressentir et il a fallu au final le jeter à la poubelle car il ne ressemblait plus à rien. C’est dommage.

  5. Julie Moynat, le dimanche 31 décembre 2017 à 16:28

    Merci à tous pour vos retours. La mise en place de ce guide de style s’est effectivement faite sur un gros projet ; ce qui a été d’autant plus difficile pour nous qui ne connaissions pas vraiment le principe au départ.
    Je prends note de vos suggestions pour y regarder de plus près. Ce n’est pas toujours évident de trouver les bons outils ; merci de les avoir partagés !