21/08/2026
Le style ne devrait pas vivre dans le HTML
Il y a deux façons de recevoir une maquette. La première est confortable : quelqu'un vous envoie une image, vous la reconstruisez dans votre outil, section par section, avec vos blocs à vous. La seconde est rapide : on colle le code de la maquette dans une section, et la page apparaît, exacte, du premier coup.
Nous faisions la seconde. Et pendant des mois, chaque page ainsi obtenue était un mur. Elle s'affichait parfaitement. Elle ne se modifiait pas.
Le problème n'est pas le HTML, c'est ce qu'on y a rangé
Un fichier HTML issu d'un outil de dessin porte deux choses qui n'ont rien à faire ensemble. Il porte la structure — cette grille contient trois cartes, chaque carte contient un titre et un texte. Et il porte l'habillage — cette carte a seize pixels de retrait, ce titre fait 3,5 rem, ce fond est légèrement transparent.
Tant que les deux vivent dans le même fichier, changer l'un veut dire éditer l'autre. Le client qui veut simplement agrandir un titre doit ouvrir du code. Il ne le fera pas. Il nous écrira un courriel, et nous le ferons pour lui — ce qui est exactement le service que notre outil est censé rendre inutile.
Nous avons donc séparé les deux. Le HTML garde la structure et le contenu. L'habillage part vivre ailleurs.
Un arbre qui dit ce que les choses sont, pas comment elles sont écrites
La première pièce est une vue « Arbre » dans le rail de l'éditeur. Elle montre la structure réelle de la section : Ligne, Colonne, Grille, Texte, Image.
Le détail qui compte est ailleurs que dans la liste : le rôle vient du CSS calculé, pas de la balise. Un <div> qui se comporte en grille s'annonce comme une grille. Un <section> qui n'aligne rien s'annonce comme un simple conteneur. C'est le navigateur, seul à voir la page rendue, qui répond — pas une déduction faite sur le nom des balises, qui se trompe dès qu'un outil de dessin exporte tout en <div>, c'est-à-dire toujours.
L'arbre se relève un niveau à la fois. Ce n'est pas une élégance : une maquette de trois cents nœuds envoyée d'un bloc dans le pont entre l'éditeur et l'aperçu fige l'interface une seconde entière. On ouvre ce qu'on regarde.
Un inspecteur qui refuse en expliquant
Cliquer un nœud ouvre un inspecteur : quarante-huit propriétés rangées en sept groupes — dimensions, position, flux, retrait, marge, apparence, texte. En tête, la portée : partout, au survol, au focus, à l'état actif, ou à partir d'une largeur d'écran donnée.
Les valeurs sont libres. On peut écrire 3.5rem, calc(100% - 2rem), var(--site-accent). C'est délibéré : une liste fermée de tailles suffit trois fois sur quatre et bloque la quatrième, celle qui compte, celle où le dessin fait quelque chose de précis.
Mais une valeur libre est une porte ouverte. La nôtre est gardée par une grammaire — une liste blanche par propriété, pas un nettoyage. La différence n'est pas académique : un nettoyage retire ce qu'il reconnaît comme mauvais et laisse passer ce qu'il ne connaît pas. Une liste blanche laisse passer ce qu'elle reconnaît comme bon et refuse le reste. Un point-virgule, une accolade, un @import, une URL en javascript:, un retour à la ligne : refusés, avec la raison écrite sous le champ.
Deux petites choses achèvent l'écran. La valeur calculée par le navigateur s'affiche en filigrane du champ, pour qu'on sache ce qu'on remplace avant de le remplacer. Et vider un champ retire le réglage au lieu de poser une valeur vide : on revient à ce que décidait la maquette. Un réglage qu'on ne sait pas annuler est un réglage qu'on n'ose pas essayer.
Où le style va vivre — et pourquoi ça change tout
L'habillage ne rentre jamais dans le HTML. Il est rangé à côté, indexé par l'identité du nœud, et devient une feuille de style engendrée.
Cette feuille est rendue par le serveur, avec le reste de la page. Trois conséquences, toutes visibles par le visiteur :
- La page ne saute pas. Notre ancienne mécanique de retouche appliquait les styles après l'hydratation : le visiteur voyait la version brute pendant une fraction de seconde, puis la page se réarrangeait sous ses yeux.
- Un moteur de recherche lit la même page que le visiteur. Ce qui est appliqué en JavaScript après coup n'existe pas pour lui.
- Un site déjà livré reçoit son habillage sans redéploiement. La publication reste instantanée, comme pour le contenu.
La feuille est écrite avec un poids de sélecteur calculé pour passer au-dessus des classes utilitaires sans jamais employer !important. Un !important gagne toujours, y compris contre celui qu'on écrira demain — c'est une dette qu'on contracte sur soi-même.
Le défaut que personne n'avait vu, et qui était le plus cher
En instrumentant tout cela, nous avons relu la fonction qui applique une retouche à un élément. Elle appelait querySelector. Au singulier.
Autrement dit : sur une grille de trois cartes identiques, seule la première était atteignable. Cliquer droit sur la deuxième carte ouvrait bien le menu, proposait bien les réglages — et les appliquait à la première. La troisième n'existait pour personne.
C'est le genre de défaut qui ne remonte jamais sous la forme d'un rapport de bogue. Il remonte sous la forme d'un client qui dit « je n'arrive pas à faire ce que je veux » et qui finit par ne plus essayer. Il vivait dans le code depuis des mois.
La correction tient en un mot — querySelectorAll et un rang — mais ce rang doit voyager : l'aperçu le calcule au clic droit, le pont le transporte, l'arbre des blocs le range, l'application le relit. Dans les deux dépôts, la console et le gabarit des sites. Une adresse d'élément n'est plus un sélecteur, c'est une paire.
Une maquette évolue — et c'est là que tout se perd
Reste le cycle. Un client renvoie la version 2 de sa maquette. Jusqu'ici, la recoller effaçait tout l'habillage posé dessus : les identités changeaient, les réglages devenaient orphelins, et rien ne le disait.
Le ré-import affiche désormais un rapport avant d'écrire : combien d'identités retrouvées, combien réinjectées, combien orphelines — et pour chaque orpheline, le nombre de réglages qu'elle rendrait inertes. Sous quatre-vingts pour cent de correspondance, une case « j'ai lu le rapport » devient obligatoire. On ne réimporte pas distraitement une chose qui peut détruire une journée de travail.
Ce qui devient orphelin n'est jamais effacé en silence. Il reste, inerte, et la porte de validation le signale. Un travail perdu doit rester visible : c'est la seule façon de le récupérer.
Le test de bout en bout a échoué du premier coup, et c'était une vraie faiblesse plutôt qu'un test mal écrit. L'empreinte d'un conteneur inclut le texte de ses enfants — donc ajouter une carte dans une grille rendait la grille elle-même orpheline. C'est-à-dire précisément quand une maquette évolue, c'est-à-dire toujours. Un cinquième signal de rapprochement le corrige : même chemin dans l'arbre, et une empreinte qui n'a fait que grandir ou rétrécir. Le conteneur reste lui-même.
Nous l'avons payé au banc d'essai. Un client l'aurait payé sur une vraie page.
Ce que nous n'avons pas construit
Le lot suivant devait ajouter un fil de commentaires par section, pour que les remarques de relecture atterrissent au bon endroit. Avant de l'écrire, nous avons relu le code existant.
Il existait déjà. Volet « Avancé » de l'inspecteur de section : ajouter une remarque, la marquer réglée, la supprimer, un compteur d'ouvertes, une icône d'avertissement sur la vignette. Construit des semaines plus tôt, oublié.
Ce qui manquait n'était pas le fil : c'était la moitié client. Un lien de relecture signé, valable sept jours, qui ouvre le vrai site publié avec une barre discrète en bas — épingler une remarque, cliquer une section, écrire deux phrases. La remarque atterrit dans le fil qui existait déjà. Zéro écran nouveau côté console.
Relire le code avant d'écrire a économisé un écran entier. C'est la règle la moins spectaculaire de notre méthode, et de loin la plus rentable.
Ce qu'on en retient
Séparer le style de la structure est une vieille idée ; l'appliquer à un CMS qui reçoit du code étranger l'est moins. Ce que la semaine a surtout montré, c'est qu'un outil doit dire : dire pourquoi il refuse une valeur, dire ce qu'un ré-import va coûter, dire qu'un réglage est devenu inerte. Un outil qui échoue en silence n'est pas un outil neutre — c'est un outil dans lequel on cesse d'avoir confiance, sans jamais savoir pourquoi.
