Pour les systèmes de conception, la cohérence et la compréhension sont essentielles. Un bon système de conception garantit la cohérence de la mise en œuvre grâce à la configuration du code qui l'implémente. Il faut que ce soit :
En utilisant ma pile par défaut de React avec Tailwind, je vais vous montrer comment définir vos propres valeurs par défaut pour la typographie, la couleur et l'espacement n'est pas seulement le point de départ pour différencier l'apparence de votre application. Plus important encore, cela réduit considérablement le code que nous devons écrire et maintenir, ce qui réduit la charge mentale liée à la mise en œuvre des styles de manière systématique, cohérente et sans erreur.
Je vais commencer par une critique majeure que je vois tout le temps, puis détailler une série d'étapes de configuration que j'utilise pour la résoudre.
Tailwind permet aux développeurs d'écrire facilement des styles, ce qui est idéal pour le prototypage rapide. Mais cette facilité ne garantit pas une bonne conception ou un système de conception évolutif et maintenable.
Les outils par défaut et sans configuration comme Tailwind constituent la couche de rythme d'infrastructure qui crée plus de temps pour la construction. Mais si vous faites évoluer une application qui utilise un système de conception pour se différencier, vous ne pouvez pas compter uniquement sur des configurations prêtes à l'emploi « gratuites comme au déjeuner ».
Si vous exécutez avec la configuration par défaut de Tailwind et poussez la gestion des styles vers l'application de classes sur les composants, le résultat est souvent un désordre de classes difficiles à raisonner réparties sur les composants, se faisant passer pour un système de conception.
Ci-dessus est un excellent exemple. C’est presque illisible et prend beaucoup de temps à comprendre, sans parler de manipuler. Les tentatives en ce sens sont très susceptibles d'entraîner des duplications et des erreurs, ce qui s'éloignera de la cohérence de la conception dans l'ensemble de l'application.
Il est facile de regrouper vos classes de conception en un seul nom de classe. Mais il n'y a aucune facilité à le savoir.
La facilité d'utilisation s'accompagne de compromis. Utiliser le standard de quelqu'un d'autre, c'est s'appuyer sur son savoir-faire. Cela peut être bénéfique, mais cela peut aussi être un piège. Prenons du recul et réfléchissons à ce que consistent les bases d'un système de conception :
Dans le contexte de React avec Tailwind, ces éléments et bien d'autres éléments du système de conception sont définis dans la configuration Tailwind, que nous pouvons personnaliser.
{/* plus joli-ignorer */}
const config = { theme: { fontSize: { /* ... */ }, colors: { /* ... */ }, spacing: { /* ... */ }, }, };
Avez-vous déjà eu du mal à vous souvenir de l'espacement correct des lettres pour votre petit texte ? Et si vous pouviez le régler une fois et l'oublier ?
Nous pouvons définir l'interlignage (hauteur de ligne) et le suivi (espacement des lettres) comme paramètres pour chaque tuple de taille de police directement dans tailwind.config. Cela signifie que nous n'avons pas besoin de définir un interligne ou un suivi lorsque nous utilisons une classe de taille de police. Pas besoin de se rappeler (ou de ne pas rechercher) quel est l'espacement des lettres d'un petit texte.
fontSize: { small: [ "13px", { lineHeight: 1.5, letterSpacing: "0.015em" }, ], base: [ "16px", { lineHeight: 1.5, letterSpacing: 0 }, ], }
L'utilisation de text-small définit désormais la taille de la police, la hauteur des lignes et l'espacement des lettres. Le fait de regrouper le tuple typographique principal dans une seule classe centralise la mise en œuvre de ces valeurs dans la configuration plutôt que dans une base de code. Une énorme victoire pour la maintenabilité.
/* 13px/1.5 with 0.015em letter-spacing */ <div className="text-small" />
Nous pouvons utiliser des variables CSS pour définir des couleurs réactives sous les scopes :root et html.dark. Cela signifie que nous écrivons et gérons une classe, comme bg-canvas, au lieu de deux, comme bg-gray-100 dark:bg-gray-800.
@import "@radix-ui/colors/gray.css"; @import "@radix-ui/colors/gray-dark.css"; :root { --color-gray-base: var(--gray-1); --color-gray-bg: var(--gray-3); --color-gray-line: var(--gray-4); --color-gray-border: var(--gray-5); --color-gray-solid: var(--gray-10); --color-gray-fill: var(--gray-12); }
Parce que j'utilise Radix Colors ici, je n'ai pas besoin de définir la portée .dark car c'est déjà fait pour moi. Si vous n'aimez pas les couleurs Radix, vous pouvez les personnaliser, utiliser une autre bibliothèque ou écrire la vôtre.
Ensuite, définissez les variables CSS dans la configuration Tailwind.
colors: { canvas: "var(--color-gray-base)", background: "var(--color-gray-bg)", line: "var(--color-gray-line)", border: "var(--color-gray-border)", solid: "var(--color-gray-solid)", fill: "var(--color-gray-fill-contrast)", }
L'utilisation de bg-canvas définit désormais la couleur appropriée en mode clair ou sombre. La suppression de cette duplication dans une base de code centralise la gestion des couleurs dans notre configuration au lieu de la répartir sur l'implémentation des classes sur les composants. Une énorme victoire pour la cognition et la maintenabilité.
/* sets --gray-1 as #fcfcfc on :root or #111111 on html.dark */ <div className="bg-canvas" />
Je préconise les noms sémantiques pour les couleurs et les tailles de police, car la dénomination sémantique est une fonction de forçage qui lie le sens à utiliser. Cela supprime les approximations de mise en œuvre et réduit les erreurs.
J'ai vu d'innombrables projets dans lesquels des gris-50, gris-100 ou gris-200 incohérents sont tous utilisés pour les arrière-plans. Ceci est facilement résolu en définissant une couleur appelée arrière-plan.
In the same way, it is easier to remember the names for dark and light text colors when they are called fill and solid. It's harder and more error-prone when they're called gray-900 and gray-600 because then you have to remember specifically that it wasn't gray-950 and gray-500, or gray-800 and gray-700.
But naming things—and agreeing on naming—is hard. In the spirit of zero-config, I suggest taking Radix Color's backgrounds, borders, solids & fills paradigm. Or this palette semantics.
And once you've set this in tailwind.config, Typescript will jog your memory at your fingertips with autocomplete.
If you're extending a Tailwind theme and not writing your own, don't use a scale key that's already been used. You may inadvertently overwrite a class that you need to use.
You'll note in the previous colour config example that I set the --color-gray-base var to canvas, not base. If I used base then using this color scale as a text colour (text-base) would clash with the default font-size base value, which is also text-base.
This isn't a downfall of customising the Tailwind config, it's a legacy of its theme naming: setting font-size or color classes in Tailwind both use text-*.1
We can also use CSS variables to set spacings.
:root { --height-nav: 80px; --height-tab: 54px; --space-inset: 20px; --container-text-px: 660px; --container-hero-px: 1000px; }
spacing: { em: "1em", /* relate icon size to parent font-size */ nav: "var(--height-nav)", inset: "var(--space-inset)", text: "var(--container-text)", hero: "var(--container-hero)", }
One could argue this is over-engineering. Except that when it comes time to compute complex interactive layouts like sticky headers, scroll margins and so on, this upfront configuration work makes it straight forward and error-free, to the pixel.
<div className="top-[calc(theme(spacing.nav)+theme(spacing.tab))]"> <div className="scroll-mt-[calc(theme(spacing.nav)+theme(spacing.tab))]"> /* ... */ </div> </div>
Note again the use of semantic naming makes it easy to remember and use.
We have now configured typography, colour and spacing tokens in a manner that is easy to understand and maintain in a single, centralised place. And we don't need to wrire as many classes to implement the system. Winning. And there's further steps we can take to reduce this implementation overhead.
What if I told you there's a way to completely avoid writing text-lg lg:text-xl xl:text-2xl p-2 md:p-4 lg:p-8 everywhere?
We can avoid setting responsive font-size classes by using clamp as a a font-size value in tailwind.config. Here's the simple clamp function I use.
fontSize: { title: [ /* clamp(17px, 14.1429px + 0.5714vw, 21px) */ generateClampSize(500, 1200, 17, 21), { lineHeight: 1.5, letterSpacing: "-0.015em" }, ]; }
So instead of writing text-lg lg:text-xl xl:text-2xl we can just write text-title. Once again, by hoisting font-size responsiveness into a clamp value, we avoid the "implement classes" pitfall again, saving mental effort, errors and debugging time.
Keep in mind, this means we've moved from text-lg lg:text-xl xl:text-2xl leading-none tracking-wide to text-title by properly configuring Tailwind. Winning!
/* 17px at 500px, 21px at 1200, fluidly calculated inbetween */ /* …with default line-height and letter-spacing also specified */ <h2 className="text-title"> Heading copy </h2>
We can also do this for spacing. When extending a theme, I prefix these keys with d for "dynamic" to differentiate it from the default spacing scale.
spacing: { /* lower value is 2/3 of upper value */ d4: generateClampSize(500, 1200, 10.5, 16), d8: generateClampSize(500, 1200, 21, 32), d16: generateClampSize(500, 1200, 43, 64), d24: generateClampSize(500, 1200, 64, 96), d64: generateClampSize(500, 1200, 171, 256), }
This allows us to write py-d24 instead of py-16 md:py-20 lg:py-24. This alleviates the weight of holding a range of website versions for each media-query in our minds. Instead it encourages us to picture fluidly responsive layouts where measurements don't matter as much as consistent relationships.
<main className="pt-d24 pb-d64 space-y-w8"> <header className="container max-w-hero space-y-1"> /* ... */ </header> <article className="container space-y-2"> /* ... */ </article> </main>
Well-crafted UI is your last defense against the coming slopwave of careless AI apps. Here's how customizing Tailwind can save you time and headaches so you can focus on the irrational amount of care it takes to build UI that works in the blink of an eye:
Yes, there's an upfront time cost. But it pays off in spades: less code, fewer errors, greater design consistency, and a team that actually understands the system.
Next up: We'll explore how to use Class Variance Authority to create a bulletproof styling API with semantic props drawn from Tailwind. Stay tuned.
This is also why I dislike using tailwind-merge to remove duplicate Tailwind classes in JSX. More often than not, I find it removing a text-color in favour of a text-fontSize when both are needed. I'm surprised more developers don't raise this issue. ↩
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!