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 Einfachheit garantiert kein gutes Design oder ein skalierbares, wartbares Designsystem.
Standardeinstellungen und Zero-Config-Tools wie Tailwind sind die Infrastruktur-Tempo-Ebene, 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“-Standardkonfigurationen 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 und beeinträchtigen die Designkonsistenz in der gesamten App.
Es ist einfach, Ihre Designklassen in einem einzigen Klassennamen zusammenzufassen. Aber es gibt keine Leichtigkeit, dies zu tun.
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: { /* ... */ }, }, };
Haben Sie jemals Schwierigkeiten gehabt, 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 */
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)", }
Die Verwendung von bg-canvas stellt jetzt die entsprechende Farbe im Hell- oder Dunkelmodus ein. 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 */
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.
Auf die gleiche Weise ist es einfacher, sich die Namen für dunkle und helle Textfarben zu merken, wenn sie als „Füllung“ und „Vollton“ bezeichnet werden. Schwieriger und fehleranfälliger ist es, wenn sie „Gray-900“ und „Gray-600“ heißen, weil man dann genau bedenken muss, dass es sich nicht um „Gray-950“ und „Gray-500“ oder „Gray-800“ und „Gray-700“ handelt.
Aber Dinge zu benennen – und sich auf die Benennung zu einigen – ist schwer. Im Sinne von Zero-Config schlage ich vor, das Hintergründe-, Rahmen-, Volumen- und Füllungsparadigma von Radix Color zu übernehmen. Oder diese Palettensemantik.
Und sobald Sie dies in tailwind.config festgelegt haben, wird Typescript Ihr Gedächtnis mit der automatischen Vervollständigung auf Trab halten.
Wenn Sie ein Tailwind-Theme erweitern und kein eigenes schreiben, verwenden Sie keinen Skalenschlüssel, der bereits verwendet wurde. Möglicherweise überschreiben Sie versehentlich eine Klasse, die Sie verwenden müssen.
Sie werden im vorherigen Farbkonfigurationsbeispiel bemerken, dass ich die Variable --color-gray-base auf Canvas und nicht auf Base gesetzt habe. Wenn ich „base“ verwenden würde, würde die Verwendung dieser Farbskala als Textfarbe (text-base) mit dem standardmäßigen Basiswert für die Schriftgröße kollidieren, der ebenfalls text-base ist.
Dies ist kein Nachteil der Anpassung der Tailwind-Konfiguration, sondern ein Vermächtnis der Themenbenennung: Das Festlegen von Schriftgröße oder Farbklassen in Tailwind verwendet beide text-*.1
Wir können auch CSS-Variablen verwenden, um Abstände festzulegen.
: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)", }
Man könnte argumentieren, dass dies ein Over-Engineering ist. Wenn es jedoch an der Zeit ist, komplexe interaktive Layouts wie Sticky-Header, Scroll-Ränder usw. zu berechnen, sorgt diese Vorab-Konfigurationsarbeit dafür, dass alles unkompliziert und fehlerfrei ist, bis auf den Pixel.
/* ... */
Beachten Sie noch einmal, dass die Verwendung semantischer Benennung das Erinnern und Verwenden erleichtert.
Wir haben jetzt Typografie-, Farb- und Abstands-Tokens so konfiguriert, dass sie leicht zu verstehen und an einem einzigen, zentralen Ort zu verwalten sind. Und wir müssen nicht so viele Klassen schreiben, um das System zu implementieren. Gewinnen. Und wir können weitere Schritte unternehmen, um diesen Implementierungsaufwand zu reduzieren.
Was wäre, wenn ich Ihnen sagen würde, dass es eine Möglichkeit gibt, das Schreiben von text-lg lg:text-xl xl:text-2xl p-2 md:p-4 lg:p-8 überall zu vermeiden?
Wir können das Festlegen responsiver Schriftgrößenklassen vermeiden, indem wir „clamp“ als Schriftgrößenwert in tailwind.config verwenden. Hier ist die einfache Klemmfunktion, die ich verwende.
fontSize: { title: [ /* clamp(17px, 14.1429px 0.5714vw, 21px) */ generateClampSize(500, 1200, 17, 21), { lineHeight: 1.5, letterSpacing: "-0.015em" }, ]; }
Anstatt also text-lg lg:text-xl xl:text-2xl zu schreiben, können wir einfach text-title schreiben. Noch einmal: Indem wir die Reaktionsfähigkeit der Schriftgröße auf einen Klammerwert heben, vermeiden wir erneut die „Implementierungsklassen“-Falle und sparen so mentalen Aufwand, Fehler und Debugging-Zeit.
Beachten Sie, dass wir durch die richtige Konfiguration von Tailwind von text-lg lg:text-xl xl:text-2xlleading-none tracking-wide zu text-title übergegangen sind. Gewinnen!
/* 17px at 500px, 21px at 1200, fluidly calculated inbetween */ /* …with default line-height and letter-spacing also specified */Heading copy
Wir können dies auch für den Abstand tun. Wenn ich ein Thema erweitere, stelle ich diesen Tasten ein d für „dynamisch“ voran, um es von der Standard-Abstandsskala zu unterscheiden.
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), }
Dadurch können wir py-d24 anstelle von py-16 md:py-20 lg:py-24 schreiben. Dies erleichtert uns die Last, für jede Medienanfrage eine Reihe von Website-Versionen im Kopf zu haben. Stattdessen ermutigt es uns, uns flüssig reagierende Layouts vorzustellen, bei denen Maße nicht so wichtig sind wie konsistente Beziehungen.
/* ... */ /* ... */
Eine gut gestaltete Benutzeroberfläche ist Ihre letzte Verteidigung gegen die kommende Welle unvorsichtiger KI-Apps. So können Sie durch die Anpassung von Tailwind Zeit und Kopfschmerzen sparen, sodass Sie sich auf die irrationale Sorgfalt konzentrieren können, die erforderlich ist, um eine Benutzeroberfläche zu erstellen, die im Handumdrehen funktioniert:
Ja, es fallen im Voraus Zeitkosten an. Aber es zahlt sich in Hülle und Fülle aus: weniger Code, weniger Fehler, größere Designkonsistenz und ein Team, das das System tatsächlich versteht.
Als nächstes werden wir untersuchen, wie man mit Class Variance Authority eine kugelsichere Styling-API mit semantischen Requisiten erstellt, die von Tailwind stammen. Bleiben Sie dran.
Das ist auch der Grund, warum ich tailwind-merge nicht gerne verwende, um doppelte Tailwind-Klassen in JSX zu entfernen. Meistens entferne ich eine Textfarbe zugunsten einer Textschriftgröße, wenn beide benötigt werden. Ich bin überrascht, dass nicht mehr Entwickler dieses Problem ansprechen. ↩
Haftungsausschluss: Alle bereitgestellten Ressourcen stammen teilweise aus dem Internet. Wenn eine Verletzung Ihres Urheberrechts oder anderer Rechte und Interessen vorliegt, erläutern Sie bitte die detaillierten Gründe und legen Sie einen Nachweis des Urheberrechts oder Ihrer Rechte und Interessen vor und senden Sie ihn dann an die E-Mail-Adresse: [email protected] Wir werden die Angelegenheit so schnell wie möglich für Sie erledigen.
Copyright© 2022 湘ICP备2022001581号-3