Tailwind v4 change l'équation du design system : la configuration vit dans le CSS, pas dans un fichier JavaScript. Résultat — aucune dépendance de config à maintenir, des tokens visibles pour tout éditeur, et un blog entier qui tient dans une seule feuille de style.
Ce que la v4 change
v3 vs v4 — où vit la configuration
| Tailwind v3 | Tailwind v4 | |
|---|---|---|
| Configuration | tailwind.config.js (JS) | CSS, via @theme |
| Import | directives @tailwind | @import "tailwindcss" |
| Custom variant | plugin JS | @custom-variant en CSS |
| Tokens couleur | objet JS | variables CSS dans :root / .dark |
Le pari CSS-first est un pari de lisibilité. Ouvrir main.css suffit
pour connaître l'entière palette du site — aucun fichier de build à lire.
Construire le système
Importer et poser le variant sombre
Déclarer les tokens sémantiques
Écrire les utilitaires signature
Un seul import, et le variant dark piloté par la classe sur <html>
(color-mode s'en charge) :
@import "tailwindcss";
@custom-variant dark (&:where(.dark, .dark *));
Les couleurs "raw" vivent dans :root / .dark, les tokens sémantiques
dans @theme inline — Tailwind en génère les utilitaires (bg-base,
text-muted, border-hairline…) :
@theme inline {
--color-base: var(--bg);
--color-elevated: var(--bg-elevated);
--color-fg: var(--text);
--color-muted: var(--text-muted);
--color-hairline: var(--line);
--font-display: 'Newsreader', Georgia, serif;
}
Ce qui fait l'identité du site est du CSS ordinaire — pas de plugin :
.hairline-t { border-top: 1px solid var(--line); }
.brand-gradient-bg { background: linear-gradient(135deg, #6366f1, #8b5cf6); }
Typographie et rayons : trois familles, une échelle
Le même @theme inline déclare les familles de polices et l'échelle de
rayons — deux tokens supplémentaires, zéro fichier supplémentaire :
--font-sans: 'Inter', ui-sans-serif, system-ui, sans-serif;
--font-display: 'Newsreader', Georgia, 'Times New Roman', serif;
--font-mono: 'JetBrains Mono', ui-monospace, 'SF Mono', monospace;
--radius-xs: 0.25rem;
--radius-sm: 0.375rem;
--radius-md: 0.5rem;
--radius-lg: 0.75rem;
--radius-xl: 1rem;
--radius-2xl: 1.5rem;
L'interface et le corps des articles restent en Inter ; les titres passent
en Newsreader, une serif éditoriale qui donne au site son identité de
« blog » ; le code est en JetBrains Mono. Et les utilitaires rounded-*
de Tailwind suivent l'échelle déclarée — un seul endroit décide si un coin
est un rounded-md ou un rounded-2xl.
Les utilitaires signature restent du CSS ordinaire. La grille de
points (.dotgrid), le dégradé de marque (.brand-gradient-bg) et les
filets (.hairline-*) sont de simples classes, partagées telles quelles
avec le site marketing — aucun plugin Tailwind à maintenir des deux côtés.
Le gain concret
Sur ce blog, l'ensemble du design system (deux thèmes, trois familles de polices, une douzaine d'utilitaires) tient dans ~200 lignes de CSS. Le passage clair ↔ sombre est instantané, sans flash, et chaque composant reste un fichier Vue sans logique de thème.
Attention aux tokens non inlinés. Un @theme sans inline émet des
variables en :root ; avec inline, Tailwind substitue les valeurs
directement — préférez inline pour des tokens qui changent avec le
thème, sinon dark: ne les suivra pas.
Pour aller plus loin
Le code de ce blog est un exemple complet : tokens sémantiques, variant dark, utilitaires signature et typographie éditoriale — à réutiliser sans retenue.