Une piste écrite 0.236fr n’est pas large de 0,236. C’est sur ce genre de détail que repose golden-grid, le composant de mise en page que je viens de publier dans la 2.6.0 d’eva-css-fluid.

Une grille à 12 colonnes est un système de division. Celle-ci est un système de proportion, et la différence se lit dans ce qu’on écrit.

Diviser ou proportionner

Dans une grille à 12 colonnes égales, on prend 4, 6 ou 8 colonnes selon ce qu’on veut faire tenir. Les proportions sont un résultat, jamais une décision. Comme toutes les colonnes se valent, il ne reste que deux façons de fabriquer une hiérarchie : centrer, ou compter.

golden-grid a quatre pistes de largeurs différentes et non interchangeables, chacune avec une fonction. Le rail (φ⁻³, 0,236) porte les métadonnées et s’aligne à droite. L’épaule (φ⁻⁴, 0,146) ne porte rien : c’est elle qui désaxe la page. Le texte (φ⁻², 0,382) est la mesure de lecture. Le débord (φ⁻³, 0,236) est là où les images partent vers la droite. Un élément ne déclare jamais une largeur : il déclare le rôle qu’il joue, et la piste lui donne sa mesure.

La page a une progression : trois bords gauches au lieu d’un milieu, et l’œil descend en suivant des bords. Le vide est une valeur : l’épaule est une piste déclarée, et aucune classe ne la vise, donc aucun contenu ne peut la récupérer. La mesure de lecture, enfin, est déduite. Pas un seul max-width: 65ch dans la feuille : c’est 0,382 de la composition.

La marge est une part de la page

Les marges sont dorées aussi, mais sur une autre unité : la marge est une part de la page, les pistes sont des parts de la composition. À 1440 px, deux marges de 80,6 et cinq gaps de 24,1 laissent 1158,2 de composition : rail 273, épaule 169, texte 442, débord 273.

Les six pistes de golden-grid et leurs fractions Une bande horizontale découpée en six segments de largeurs inégales. Aux deux extrémités, les marges, chacune 0,056 de la page. Entre elles, quatre pistes : le rail à 0,236, l'épaule à 0,146 marquée plus fort parce qu'elle reste vide, le texte à 0,382 qui est le segment le plus large, et le débord à 0,236. Un trait au-dessus mesure la page entière, un trait en dessous mesure seulement les quatre pistes centrales, appelées la composition. LA PAGE = 1 0,056 0,236 0,146 0,382 0,236 0,056 marge rail épaule texte débord marge LA COMPOSITION = 1
Deux unités : les marges sont des parts de la page, les pistes des parts de ce qu'elles laissent.

Cinq gaps, et la série s’arrête là

Le gap est l’air entre les pistes, il relève de l’échelle : il n’y a que deux marges, mais cinq gaps, et je préfère une incohérence formelle assumée à une cohérence qui vide la composition. Le calcul est dans la doc d’EVA, avec la géométrie des pistes et de la marge.

L’incohérence est sans conséquence, et ça se vérifie. column-gap est prélevé avant la distribution des fr : les quatre pistes se partagent ce qui reste, leurs rapports ne bougent pas. En poussant le gap de 4 px à 103 px dans le navigateur, la composition passe de 1413 à 920 px et les fractions restent 0,2360 / 0,1460 / 0,3820 / 0,2360.

La composition rétrécit, les quatre parts ne bougent pas Deux bandes horizontales superposées, chacune découpée en quatre segments. La bande du haut, mesurée avec un gap de 4 pixels, fait 1413 pixels de composition. La bande du bas, mesurée avec un gap de 103 pixels, n'en fait plus que 920 et se voit nettement plus courte. Sous chaque segment des deux bandes, la même fraction est inscrite : 0,2360 pour le rail, 0,1460 pour l'épaule, 0,3820 pour le texte, 0,2360 pour le débord. GAP 4 PX COMPOSITION 1413 PX 0,2360 0,1460 0,3820 0,2360 GAP 103 PX COMPOSITION 920 PX 0,2360 0,1460 0,3820 0,2360
493 px de composition en moins, et les quatre parts identiques à la quatrième décimale.

subgrid fait le vrai travail

grid-template-columns: subgrid hérite des pistes et de leurs noms : un bloc écrit grid-column: rail sans rien savoir de la page qui le contient. C’est aussi le plancher de compatibilité réel du composant : Chrome 117, Safari 16, Firefox 71, partout depuis septembre 2023.

Deux échecs muets

Le premier tient dans deux caractères. Une piste écrite 0.236fr s’écrit en réalité minmax(auto, 0.236fr), et ce minimum automatique est la contribution min-content du contenu : une URL non sécable dans le rail élargit la piste et casse la proportion dorée. Rien dans la console, juste une page qui n’est plus dorée. Le composant écrit donc minmax(0, …) sur ses quatre pistes.

Le second est dans l’ordre de deux sélecteurs.

.blocks > * { grid-column: main; }   // le défaut du flux
.rail       { grid-column: rail; }   // le placement

Ces deux sélecteurs ont la même spécificité, 0,1,0. Dans cet ordre, tout va bien. Dans l’autre, le défaut écrase toutes les classes de placement, et rail, blocs larges et débords retombent silencieusement dans la colonne de texte. Le CSS reste valide, la page reste valide, la grille ne l’est plus.

Ce que ça coûte

Rendre les marges dorées coûte de la mesure de lecture. Elle passe de 60 à 53 signes environ à 1440 px. C’est encore dans la plage confortable, entre 45 et 75, mais c’est un arbitrage.

Le composant est optionnel et n’émet aucune règle tant qu’on ne l’active pas.

@use 'eva-css-fluid' with ($golden-grid: true);

Sans Sass, dist/golden-grid.css fait 2,1 Ko et se pose après eva.css, dont il consomme les variables.