Catégories
CSS javascript React

Où je dis du bien du CSS-in-JS

Il n’y a que les imbé­ciles qui ne changent pas d’avis et c’est mon avis depuis toujours

Coluche

J’ai toujours regardé avec dédain les tenta­tives des dev JS pour contour­ner l’écri­ture de CSS mais je commence à consi­dé­rer que les outils de CSS-in-JS type Emotion sont la bonne solu­tion pour les webapp React.


J’ai été inté­gra­teur, à faire de la belle CSS sépa­rée du code HTML. On finit quand même vite par construire des monstres ou se prendre les pieds dans le tapis dès qu’on fait plus de quelques pages types.

Pour résoudre le problème, élimi­nons le. C’est ce que proposent les conven­tions comme BEM. Si je cari­ca­ture, il s’agit prin­ci­pa­le­ment de reti­rer les sélec­teurs CSS un attri­buant une ou plusieurs classes spéci­fiques à chaque contexte. C’est fran­che­ment moche mais ça fonc­tionne.

CSS-Modules va un peu plus loin. Le prin­cipe est le même mais on permet au déve­lop­peur d’uti­li­ser un nommage plus agréable. C’est l’ou­til de géné­ra­tion qui gère la complexité au lieu du déve­lop­peur.


J’avoue que j’aime bien CSS-modules. C’était mon favori jusqu’à présent.

Ça revient à juste gérer un fichier par compo­sant en se limi­tant à des sélec­teurs très simples pour ne pas créer de conflits de spéci­fi­cité. On reste sur du CSS stan­dard et sur une approche proche de mes habi­tudes histo­riques. Mieux : L’in­té­gra­tion peut se faire indé­pen­dam­ment du langage de déve­lop­pe­ment de l’ap­pli­ca­tif.

C’est top mais ça se base sur des compo­sants qui ne bougent pas beau­coup, dont on connait à l’avance tous les états.

Dès qu’il s’agit de cumu­ler plusieurs états, le résul­tat dépend de l’ordre d’écri­ture dans la CSS. Parfois c’est bien prévu, parfois non.

Dès qu’il s’agit de rendre des choses très dyna­miques, il faut de toutes façons sortir des CSS modules. Vous voulez que dans la vue large les items de navi­ga­tion se colorent au survol en fonc­tion de la caté­go­rie desti­na­tion déter­mi­née dyna­mique­ment mais qu’ils utilisent la couleur neutre dans la vue réduite desti­née aux mobiles ? Vous êtes à poil et il va falloir compo­ser avec d’autres façons d’injec­ter des CSS, peut-être même tâton­ner sur les prio­ri­tés entre classes.


Les classes utili­taires et CSS atomiques à la Tachyon sont là pour indus­tria­li­ser en pous­sant encore plus loin.

J’ai une classe par valeur à appliquer : .ms7-ns applique la septième valeur du cata­logue (7) comme taille hori­zon­tale maxi­mum (ms pour max-width) si la fenêtre a une taille supé­rieure au point de rupture « small » (ns pour non-small).

Ça n’offre quasi­ment aucune abstrac­tion utile (unifor­mi­ser les valeurs on a déjà plein d’ou­tils plus effi­caces). C’est vite cryp­tique, lourd, et mons­trueux dès qu’on multi­plie les valeurs et les points de rupture possibles.

Le seul inté­rêt par rapport à écrire direc­te­ment les attri­buts style c’est que ça permet d’ac­cé­der aux media query et aux pseudo-sélec­teurs.

Malheu­reu­se­ment non seule­ment ça ne résout pas les conflits de prio­ri­tés mais ça les empire. Si je spécia­lise un compo­sant exis­tant en y ajou­tant une classe liée à une direc­tive déjà présente, je joue à la roulette russe. Il faut abso­lu­ment que mon compo­sant initial prévoit lui-même tous les cas possibles pour savoir quelle classe injec­ter et ou ne pas injec­ter. Pas d’al­ter­na­tive.

J’ai vrai­ment l’im­pres­sion d’un retour en arrière mons­trueux avec ces CSS atomiques, cumu­ler les défauts sans aucun avan­tage, et c’est proba­ble­ment ce qui m’a fait reje­ter par prin­cipe les CSS-in-JS jusqu’a­lors.


Les CSS-in-JS c’est fina­le­ment pous­ser la logique de Tachyons un cran plus loin. Quitte à déci­der de tout dans le code HTML, autant écrire direc­te­ment les styles à cet endroit là en utili­sant la vraie syntaxe CSS et en y ajou­tant la possi­bi­lité d’ac­cé­der aux media query et aux pseudo-sélec­teurs.

Emotion c’est ça. On est à la croi­sée entre le « j’écris tout dans un attri­but style » et le « j’at­tache un module CSS ».

En fonc­tion­ne­ment basique c’est comme un CSS module sans le sélec­teur. Je donne les direc­tives en CSS on ne peut plus clas­siques et j’ai accès aux media query, aux pseudo-sélec­teurs et aux anima­tions avec une syntaxe proche de ce que font les prépro­ces­seurs habi­tuels (et en phase avec la direc­tion que prend la syntaxe CSS elle-même).

const style = css`
padding: 32px;
background-color: hotpink;
font-size: 24px;
border-radius: 4px;
&:hover {
color: blue;
}
`

Je peux direc­te­ment ajou­ter le résul­tat aux classes CSS de mon compo­sant. Il se char­gera de géné­rer un nom de classe, de créer la CSS corres­pon­dante dans le docu­ment, et de lier les deux, comme avec CSS-Modules.

L’exemple est peu parlant. On a juste l’im­pres­sion d’un CSS-Modules écrit dans le fichier JS.

L’avan­tage c’est que je ne suis pas limité aux valeurs en dur. Je peux avoir des valeurs dyna­miques venant de mon Javas­cript ou de mon thème, et je n’en limite pas les effets à ce que me permettent les variables CSS.

Je peux aussi réuti­li­ser, compo­ser ou surchar­ger un élément ou un bloc de styles avec un autre sans risque de conflit de prio­rité.


Tachyons me donnait l’im­pres­sion de cumu­ler les incon­vé­nients, ici j’ai vrai­ment l’im­pres­sion de cumu­ler les avan­tages.

La seule contrainte c’est que mon code CSS se retrouve dans mes fichiers JS. C’est moche quand c’est dit ainsi mais pour une app en React, on a de toutes façons un fichier par compo­sant HTML et ça a du sens de grou­per HTML, JS et CSS lié au compo­sant ensemble quand ils sont forte­ment liés. C’est d’ailleurs le choix de VueJS.

Ce n’est forcé­ment pas adapté à tout, et si vous voulez rester géné­riques les CSS-Modules sont à mon avis l’op­tion la plus saine, mais pour un code React je crois que c’est là que je commen­ce­rai par défaut désor­mais.

Catégories
CSS

Rempla­cer du texte par une image en CSS

Dans les années 2007 à 2009 on avait une collec­tion d’hor­ribles bidouilles CSS pour insé­rer des images à la place de certains textes via CSS. L’idée c’est que certaines images ne sont pas du contenu mais bien de la présen­ta­tion, poten­tiel­le­ment dépen­dantes du contexte.

Le besoin était tel que c’était un des sujets les plus en vue en CSS pendant des années avec « comment centrer un contenu verti­ca­le­ment ».

h3.nir {
   height: 75px;
   width: 300px;
   overflow: hidden;
   margin: 0;
   padding: 0;
 }
 h3.nir:before {
   content: url(http://…/test.png);
   display: inline-block;
   font-size: 0;
   line-height: 0;
 }

Fran­che­ment c’était de la bidouille de haut vol, avec plein de défauts. On rêvait d’un truc plus simple, qui fonc­tionne correc­te­ment quand l’image ne se charge pas et sur les lecteurs d’écran, sans flash de contenu non stylé. Je me demande même ce qui suit n’a fonc­tionné sur certains navi­ga­teurs, mais on n’y est visi­ble­ment pas encore :

h3 { content: url(http://…/test.png); }

CSS a beau­coup évolué, les navi­ga­teurs aussi. J’es­pé­rais qu’on avait enfin résolu ce problème ultra bateau. Visi­ble­ment non. La seule solu­tion passe par des polices de carac­tères d’icônes et des recon­nais­sances de liga­ture. Le reste n’a que peu changé en 10 ans, on a juste enlevé les besoins de compa­ti­bi­lité sur les vieux navi­ga­teurs.

J’avoue que je ne comprends pas. On ajoute des fonc­tion­na­li­tés de folie et on ne gère toujours pas la base qui a généré des milliers de pages en bidouilles de contour­ne­ment. Qu’on m’ex­plique…