Article publié initialement le 11 mars 2020, corrigé et complété
Tel le marronnier de l’intégration web, j’ai vu réapparaitre régulièrement au fil des années, l’idée de replacer dans le HTML des attributs de mise en forme. Au départ, on avait les “vrais” attributs de mise en forme HTML. Rappelez-vous : valign, align, margin, etc.
C’était pratique, mais ça, c’était en 1998. Et puis avec CSS Zen Garden, on a découvert que séparer fond (HTML) et forme (CSS), c’était quand même bien pratique : le fait de découpler la mise en forme du HTML avait beaucoup d'avantages. Donc on a mis cette histoire de déclaration de la mise en forme dans le HTML de côté.
Bootstrap a relancé l’idée, avec ses Utilities : border-top-0
, position-absolute
, etc. Et encore une fois, ces Utilities, bien qu’utiles, posaient des problèmes :
- problème de séparation du fond et de la forme : CSS est plus ou moins une librairies de styles, et la mise en forme est faite dans le HTML :/
- problème de spécificité : si je prends le border-top de Bootstrap 4, par exemple, on tombe sur une règle de ce type : border-top: 1px solid #dee2e6 !important;. Bon, ça c’est le problème de Bootstrap. Mais quand même, en empilant des classes qui n’ont aucun rapport les unes avec les autres, on a vite fait des créer des conflits de règles. Exemple :
<div class=”text-center border-danger sr-only position-relative border-top ml-1 px-1”>
<!-- 🧐 1. de quelle couleur sera la bordure du haut ? -->
<!-- 😓 2. mais attend, c'est quoi sur la maquette ce bout de HTML ? -->
- problème de lisibilité : en définissant les éléments d’interface (les unités d’informations) comme en empilement, sans logique, de classes de mise en forme, on ne savait plus trop bien à quoi correspondait, dans l’interface, l’élément sur lequel on bossait.
- problème de maintenance : une évolution ? un bug à corriger ? Imaginez revoir tous les boutons sur votre intégration, pour leur apporter un border-radius, ou bien ajuster le padding, ou un truc du genre. Bon courage.
Alors bon, ça nous faisait marrer de revoir des trucs comme ça. Pour du prototypage, ça fait le boulot, mais pour de l’intégration durable, passons. Mais ça c’était avant, et maintenant, on a du neuf : Utility-First CSS.
En gros, en pied de nez aux méthodos orientées composants (OOCSS, BEM, etc.), qui place le composant d’abord, exemple :
<a href="https://www.google.fr" class="button">
<span class="button__label">Mon bouton</span>
</div>
Le logique Utility-First CSS propose quelque chose comme :
<a href="https://www.google.fr" class="text-center border-blue background-white padding-20 text-bold display-ib">
<span class="button__label">Mon bouton</span>
</div>
Vous noterez le concept particulièrement novateur :
- plus de problème de nommage : y’en a plus
- donc si on ne nomme plus, on va plus vite à taper du code
Mais :
- aucun d’aspect sémantique (c'est l'idée)
Je m’imagine reprendre une inté qui a été initialement faite comme ça, et les questions qui me viendraient (NB: toutes mes remarques sont issues de mises en situation imaginaires avec des équipes en production) :
- plus de liens avec l’architecture de l’information définie dans la maquette (comment savoir, dans le code, quelle unité d’information est représentée ?) : alors oui, un bon découpage de templates peut faire le boulot, mais d’une façon ou d’une autre, a minima, le debug ne sera pas une partie de plaisir.
- c’est subjectif, mais je me dis : et la lisibilité là-dedans ? Je reprends une tartine de HTML écrite comme ça => 🚪. Plus sérieusement, le temps passé juste à comprendre quel élément est où / fait quoi ne me semble pas du tout négligeable.
- si on va plus vite à tomber l’intégration d’un élément, je pense que sur le long terme, on y passe beaucoup plus de temps (cf. plus haut, mon exemple du bouton avec Bootstrap).
- comment maintenir une cohérence dans l’interface : il arrive qu’on m’appelle pour me demander de resserrer les vis sur des intégrations qui ont été faites et où il y a pas mal d’incohérences, sur les mêmes composants (dans les maquettes, tout du moins) d’une page à l’autre du site. Utility-First est voué à produire des incohérences de ce genre : un bouton à un endroit n’a pas de lien avec un bouton à un autre endroit (sauf si on a un système de vues bien découpé - React, Vue, etc).
Plus généralement, le concept de composants s’est fait une place de choix dans tous les métiers de l’interface : UX designer, UI designer, dev front, parlent déjà tous de composants d’interface / d’unités d’informations.
Depuis plusieurs années, le dialogue s’est simplifié : de manière transverse, chaque métier peut discuter avec les autres en parlant des mêmes choses : des composants d’interface.
Pourtant, c’est comme si en 2017, un intégrateur c’était dit : fuck, allez-vous faire foutre, moi j’aimais bien Bootstrap, je vais faire les trucs à ma sauce.
Designer : “il faut qu’on retouche le composant d’avatar utilisateur”
Intégrateur : “tu parles de<div class=”margin-20 text-center border-solid background-white padding-30 border-radius-50” />
?”
Cette méthodo supprime tout l’aspect nommage / sémantique de classes CSS. Pourtant, on a besoin de cet aspect : pour discuter, pour s’y retrouver, pour définir des éléments réutilisables.
Alors qui fait le boulot si ce n’est plus les classes ?
La seule solution qui me vient à l’esprit, c’est que c’est le templating qui reprend ce boulot. Effectivement, si vous avez un composant React de (notez qu’au final, j’ai quand même dû nommer un composant…), vous stockez toutes vos classes et vous créez vos conditions dans ce composant, et l’affaire est a priori réglée. Bon, le debug sera un peu moins simple quand même. Mais à part des systèmes de templating / des moteurs de vues de ce genre qui déclarent des composants, je m’imagine mettre ça en place dans un Twig, ou dans un WP :
J’ai vraiment essayé de retourner le pour et le contre.
Les "pours" :
- dans le cas des frameworks basés sur ces systèmes (Tailwind par exemple), on a pas besoin de bien connaître CSS pour faire de l'intégration : on peut avoir des profils plus variés qui peuvent faire évoluer l'interface.
- sur l’intégration de départ, on peut gagner un peu de temps. On ne nomme pas, c’est effectivement un gain de temps en soi. Mais le nommage, comme je l’ai dit, on en a besoin. Vous pouvez mettre le problème sous le tapis, il n’en reste pas moins qu’il faudra trouver un nom à votre bouton à un moment où à un autre.
- on répète moins de CSS, mais on répète énormément de HTML.
Pour les contres, j’en vois un paquet, je ne vais pas revenir sur ceux déjà évoqués, mais en plus :
- une logique Utility-first, ça peut se tenter sur un système de vues bien découpé (React, Vue, etc). On reporte juste le nommage ailleurs en fait. Je pars quand même du principe que notre intégration, en tout ou partie, ne doit pas trop dépendre du moteur de vues (= ce qui produit le HTML), pour, au besoin, faire évoluer toutes ces technos en gardant un maximum des éléments graphiques déjà intégré
- je ne suis pas non plus un grand fan du fait de devoir apprendre trop de choses concernant un framework ou une lib. En l'occurrence, si on prend l'exemple de Tailwind, il y a pas mal de vocabulaire à apprendre pour commencer à bosser de façon efficace. Je pars du principe que ce temps d'apprentissage en dehors du langage est du temps potentiellement perdu. Ce temps passé, cette montée en compétence dépend complètement de l'outil, de son créateur, de ses montées en version (là où concernant un langage, surtout côté front, ce genre de choses est discuté, débattu et "ratifié", sans oublier le "Don't break the web").
À noter que la réflexion de base d'Adam Wathan qui a conduit à la création de Tailwind CSS par exemple, est pas inintéressante du tout (j'avais beaucoup apprécié cet article), mais ses conclusions sont très subjectives je trouve. Notamment la section qui pose la question de revenir à du CSS inline et dont le principal argument contre est que ça pose trop de possibilités, alors qu'un ensemble de classes connues limites les choix.
On pourrait rétorquer qu'à ce compte là, on peut aussi définir des sets de valeurs en variables CSS, ça reviendrait au même et ce serait probablement plus performant 🤫
Pour aller plus loin :
- https://adamwathan.me/css-utility-classes-and-separation-of-concerns/
- j’ai lu https://frontstuff.io/in-defense-of-utility-first-css, et d’autres articles “défendant” Utility-First CSS (je me suis dit qu’il y avait déjà un souci)
- j’ai regardé ce que faisait https://tailwindcss.com/
Top comments (5)
Je pensais moi aussi qu'il s'agissait d'une parodie, mais force de constaté que seul Tailwind en est une. Tailwind:
J'utilise depuis un moment maintenant WindiCSS, qui est basé sur Tailwind mais :
<md:bg-blue-500 bg-blue-300
Force de constater que créer des class css met le bazar dans les différents projets, ne sachant plus forcément à quoi servent chacune des class, chose que Tailwind (Windi dans mon cas) résout.
Et vous utilisez ça accompagné de quelle techno pour rendre le HTML ?
Tout dépends des projets, mais soit un projet avec ViteJS, soit Svelte Kit. Dans tous les cas, Svelte kit est aussi basé sur Vite
I'm convinced utility-first frameworks are a kind of parody. "What's the daftest framework I can come up with, and can I convince people to use it"
Well if I have some spare time, I'll translate it in english :)