Files
design-system/PROTOCOLE.md
T

6.4 KiB

PROTOCOLE — design system trans-former.fr

La « matrice » : les règles que tout site de la constellation applique. Un build n'est pas fini tant que la Definition-of-Done en bas n'est pas cochée.

1. Mobile-first — règle de base

  • Les styles de base ciblent 360px. On monte ensuite avec des media queries min-width uniquement (jamais max-width pour la structure ; une exception encadrée : l'état hamburger de la Nav).
  • Typographie fluide en clamp() — l'échelle --fs-* est calibrée entre 360px et 1280px, ne pas la redéfinir par breakpoint.
  • Cibles tactiles ≥ 44px (boutons, liens de nav, toggles). Sur pointer: coarse, aucune taille ne descend en dessous.

Breakpoints — constantes

Les variables CSS ne fonctionnent pas dans @media : ces valeurs sont des constantes de la constellation, à utiliser telles quelles partout.

Nom px rem Usage type
base 360 — styles par défaut (pas de media query)
sm 480 30rem ajustements petits écrans larges
md 768 48rem passage nav inline, grilles 2-3 col
lg 1024 64rem layouts larges
xl 1280 80rem plafond de l'échelle fluide

Écrire les media queries en rem (@media (min-width: 48rem)).

2. Motion charter

  • Motion piloté-utilisateur : toute animation répond à une action (scroll, hover, focus, clic). Jamais d'auto-play — pas de carrousel automatique, pas d'animation en boucle — sans pause au survol/focus et contrôles visibles.
  • @media (prefers-reduced-motion: reduce) coupe tout mouvement non essentiel. Le kill-switch global est dans reset.css ; tout JS d'animation doit aussi tester matchMedia("(prefers-reduced-motion: reduce)") (cf. js/reveal.js).
  • Budget reveal : fade + translate court (≤ 12px), durées --dur-base/--dur-slow max, easing --ease-out. Pas de zoom, pas de rotation, pas de parallaxe décorative.
  • Le JS est progressif : sans JS, rien n'est masqué, rien n'est cassé (garde html[data-js]).

3. Lois design (anti-patterns) — appliquées sans exception

  • ❌ border-left/border-right > 1px colorée comme accent (card, callout)
  • ❌ gradient text (background-clip: text)
  • ❌ glassmorphisme décoratif par défaut
  • ❌ template hero-metric (grand chiffre + petit label + gradient accent)
  • ❌ grilles de cards identiques icon+heading+text
  • ❌ modal comme premier réflexe UX
  • ❌ em-dashes (— / --) dans les textes UI
  • ❌ Inter par défaut sans raison
  • ❌ gradients violets sans justification
  • ❌ dark glow décoratif

4. Tokens — conventions de nommage

  • Nommage par rôle, jamais par couleur brute : --primary, pas --green. Un thème peut changer toute la palette sans toucher un composant.
  • Préfixes d'échelle : --fs-* (font-size), --lh-* (line-height), --fw-* (weight), --space-*, --radius-*, --shadow-*, --dur-*, --ease-*, --z-*.
  • Paires de contraste : --primary/--on-primary, --accent/--on-accent. Toujours utiliser le on-* correspondant comme couleur de texte sur ces fonds.
  • Layers : tokens.css vit dans @layer tf-tokens, reset.css dans @layer tf-reset. Les thèmes et le CSS des sites restent non-layerés → ils gagnent toujours sur la fondation, quel que soit l'ordre de chargement. Ne jamais mettre un thème dans un layer. (Exception voulue : le kill-switch reduced-motion du reset est en !important layeré, il bat donc tout le monde.)
  • Le schéma (noms + échelles) est universel et gelé : en ajouter demande une mise à jour ici + dans tokens.css + dans les thèmes. En retirer/renommer = breaking change pour tous les sites.
  • Tailwind 4 (site racine) : les tokens sont mappés via tailwind.css (@theme inline). Les namespaces en collision de nom (--font-*, --radius-*, --shadow-*, --ease-*) s'utilisent en syntaxe var arbitraire : rounded-(--radius-md), shadow-(--shadow-md), ease-(--ease-out), font-(family-name:--font-heading).

5. Ajouter un thème (nouveau site)

  1. cp theme/base.css theme/mon-site.css
  2. Remplacer palette claire, palette sombre (bloc [data-theme="dark"] et duplication @media (prefers-color-scheme: dark) avec le garde :not([data-theme="light"])), et les deux stacks de polices.
  3. Ne toucher à rien d'autre : pas d'échelles, pas de spacing, pas de motion dans un thème.
  4. Vérifier les contrastes AA (4.5:1 texte courant, 3:1 grands titres/UI) dans les deux modes — y compris --on-primary sur --primary et --on-accent sur --accent.
  5. Charger les @font-face côté site (self-host / fontsource) ; le thème ne définit que les stacks.
  6. L'ajouter à la page démo (src/pages/demo/mon-site.astro, 4 lignes) et valider le kitchen sink.

Clair/sombre : mode clair par défaut + sombre via préférence système, le toggle explicite (data-theme) gagne toujours dans les deux sens. Un site peut être sombre par défaut (cf. theme/aep.css : :root sombre, variante claire sur [data-theme="light"] seulement).

6. Accessibilité — socle

  • Contraste AA partout, dans les deux modes.
  • Focus visible partout : :focus-visible global dans reset.css, ne jamais le supprimer sans remplacement équivalent.
  • Navigation clavier complète : hamburger avec aria-expanded/aria-controls, fermeture Échap, focus trap panneau ouvert, skip-link (BaseLayout).
  • lang défini sur <html> (prop de BaseLayout), aria-current="page" sur le lien actif, alt sur toute image porteuse de sens.

7. Definition-of-Done — checklist de fin de build

Avant de déclarer un site « fini » :

  • Testé à 360, 768, 1280 px — aucun débordement horizontal, hiérarchie lisible aux trois tailles.
  • Testé en clair ET sombre (préférence système + toggle) — contrastes AA dans les deux.
  • Testé avec prefers-reduced-motion: reduce — plus aucun mouvement non essentiel.
  • Testé sans JS — contenu et navigation accessibles (liens visibles, rien de masqué).
  • Navigation clavier seul : tout est atteignable, focus visible, hamburger Échap + trap OK.
  • Cibles tactiles ≥ 44px sur mobile.
  • Zéro valeur en dur qui duplique un token (couleur hex, taille de police, spacing) dans le CSS du site.
  • Aucune violation des lois design (§3).
  • Le site n'importe qu'un seul theme/*.css ; en changer suffit à changer le look.
  • Lighthouse a11y ≥ 95, aucune erreur console.