Für Designsysteme sind Konsistenz und Verständnis alles. Ein gutes Designsystem gewährleistet die Konsistenz der Implementierung durch die Konfiguration des Codes, der sie implementiert. Es muss sein:
Anhand meines Standardstapels von React with Tailwind zeige ich Ihnen, dass das Festlegen Ihrer eigenen Standardeinstellungen für Typografie, Farbe und Abstände nicht nur der Ausgangspunkt für die Differenzierung des Erscheinungsbilds Ihrer App ist. Noch wichtiger ist, dass dadurch der Code, den wir schreiben und pflegen müssen, drastisch reduziert wird, was die mentale Belastung durch die systematische, konsistente und fehlerfreie Implementierung von Stilen verringert.
Ich beginne mit einem Hauptkritikpunkt, den ich ständig sehe, und erläutere dann eine Reihe von Konfigurationsschritten, mit denen ich ihn löse.
Tailwind erleichtert Entwicklern das Schreiben von Stilen, was sich hervorragend für schnelles Prototyping eignet. Aber diese Leichtigkeit garantiert kein gutes Design oder ein skalierbares, wartbares Designsystem.
Standardeinstellungen und Zero-Config-Tools wie Tailwind sind die Taktebene der Infrastruktur, die mehr Zeit für den Aufbau schafft. Aber wenn Sie eine App skalieren, die ein Designsystem nutzt, um sich von anderen abzuheben, können Sie sich nicht ausschließlich auf „kostenlos wie in der Mittagspause“-Out-of-the-Box-Konfigurationen verlassen.
Wenn Sie mit der standardmäßigen Tailwind-Konfiguration arbeiten und die Stilverwaltung auf die Anwendung von Klassen auf Komponenten übertragen, ist das Ergebnis oft ein Durcheinander von schwer zu begründenden Klassen, die über Komponenten verteilt sind und sich als Designsystem tarnen.
Oben ist ein Paradebeispiel. Es ist fast unleserlich und erfordert viel Zeit, es zu verstehen, geschweige denn zu manipulieren. Versuche, dies zu tun, führen höchstwahrscheinlich zu Duplikaten und Fehlern, wodurch die Designkonsistenz in der gesamten App beeinträchtigt wird.
Es ist einfach, Ihre Designklassen in einem einzigen Klassennamen zusammenzufassen. Aber es gibt dabei keine Leichtigkeit des Wissens.
Benutzerfreundlichkeit geht mit Kompromissen einher. Den Standard eines anderen zu verwenden bedeutet, sich auf dessen Know-how zu verlassen. Das kann von Vorteil sein, aber auch eine Falle sein. Lassen Sie uns einen Schritt zurücktreten und darüber nachdenken, woraus die Grundlagen eines Designsystems bestehen:
Im Kontext von React with Tailwind werden diese und viele andere Designsystemelemente in der Tailwind-Konfiguration festgelegt, die wir anpassen können.
{/*prettier-ignore*/}
const config = { theme: { fontSize: { /* ... */ }, colors: { /* ... */ }, spacing: { /* ... */ }, }, };
Hatten Sie jemals Schwierigkeiten, sich den richtigen Buchstabenabstand für Ihren kleinen Text zu merken? Was wäre, wenn Sie es einmal einstellen und dann vergessen könnten?
Wir können Zeilenabstand (Zeilenhöhe) und Nachlauf (Buchstabenabstand) als Parameter für jedes Schriftgrößen-Tupel direkt in tailwind.config festlegen. Das bedeutet, dass wir weder Zeilenabstand noch Zeilenabstand festlegen müssen, wenn wir eine Schriftgrößenklasse verwenden. Sie müssen sich nicht merken (oder nicht nachschlagen), wie groß der Buchstabenabstand bei kleinem Text ist.
fontSize: { small: [ "13px", { lineHeight: 1.5, letterSpacing: "0.015em" }, ], base: [ "16px", { lineHeight: 1.5, letterSpacing: 0 }, ], }
Mit text-small werden jetzt Schriftgröße, Zeilenhöhe und Buchstabenabstand festgelegt. Durch das Zusammenfassen des typografischen Kerntupels in einer Klasse wird die Implementierung dieser Werte in der Konfiguration zentralisiert und nicht in einer Codebasis. Ein großer Gewinn für die Wartbarkeit.
/* 13px/1.5 with 0.015em letter-spacing */ <div className="text-small" />
Wir können CSS-Variablen verwenden, um reaktionsfähige Farben in den Bereichen :root und html.dark festzulegen. Das bedeutet, dass wir eine Klasse schreiben und verwalten, wie zum Beispiel bg-canvas, statt zwei, wie zum Beispiel 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); }
Da ich hier Radix Colors verwende, muss ich den .dark-Bereich nicht festlegen, da dies für mich bereits erledigt ist. Wenn Ihnen die Radix-Farben nicht gefallen, können Sie sie anpassen, eine andere Bibliothek verwenden oder Ihre eigene schreiben.
Dann legen Sie die CSS-Variablen in der Tailwind-Konfiguration fest.
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)", }
Mit bg-canvas wird jetzt die entsprechende Farbe im Hell- oder Dunkelmodus eingestellt. Durch das Entfernen dieser Duplizierung in einer Codebasis wird das Farbmanagement in unserer Konfiguration zentralisiert, anstatt es auf die Implementierung von Klassen in Komponenten zu verteilen. Ein großer Gewinn für Erkenntnis und Wartbarkeit.
/* sets --gray-1 as #fcfcfc on :root or #111111 on html.dark */ <div className="bg-canvas" />
Ich befürworte semantische Namen für Farben und Schriftgrößen, da die semantische Benennung eine erzwingende Funktion ist, die die Bedeutung mit der Verwendung verknüpft. Dadurch entfällt das Rätselraten bei der Implementierung und die Fehlerquote wird reduziert.
Ich habe unzählige Projekte gesehen, bei denen inkonsistente Grautöne 50, Grau 100 oder Grau 200 für Hintergründe verwendet wurden. Dies lässt sich leicht lösen, indem man eine Farbe namens Hintergrund definiert.
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. ↩
Das obige ist der detaillierte Inhalt vonTailwind als Designsystem konfigurieren. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!