Utility-First CSS
DIE Lösung für wartbares CSS?
07. April 2021
6 min
Wer schon mal eine größere Web-App gepflegt hat, kennt sicher den Punkt, an dem es sich so anfühlt, als könnte man am CSS nur noch Neues hinzufügen. Alles, was man bearbeitet, hat unvorhersehbare Auswirkungen.
Das CSS hat also gewonnen.
Mir ging das auf jeden Fall schon des Öfteren so. Und was bei mir dann meistens passiert, ist dass ich automatisch aufhöre, möglichst semantisches CSS zu schreiben. Stattdessen fange ich an, mit möglichst kleinen, wiederverwendbare Klassen zu arbeiten, die wenig unterschiedlichen Dinge tun.
Dieses Vorgehen hat einen Namen und inzwischen einen berechtigten Platz in der Welt der Web-Entwicklung: Utility-First CSS (auch als Atomic CSS bekannt).
Beim Entwickeln meiner neuen Website habe ich die Methodologie direkt ab dem Start ausprobiert.
Was heißt Utility-First?
Mit Utility CSS-Klassen meint man solche, die genau eine Funktion haben und diese auch durch ihren Namen ausdrücken. Der Name der CSS-Klasse beschreibt also nicht semantisch das Element, für das die Klasse benutzt wird, sondern beschreibt das, was sie damit macht. Eine Utility-Klasse könnte also beispielsweise den Abstand beeinflussen und eine andere die Hintergrundfarbe. Solch eine Klasse beeinflusst also nicht mehrere Eigenschaften des HTML-Elements. Im HTML werden dann mehrere Utility-Klassen komponiert, um Elemente darzustellen.
Klassisch sematisch:
Utility-First:
Warum dann nicht direkt mit Inline Styles arbeiten? Der Grund ist relativ einfach: Mit Inline Styles stehen einem wichtige Funktionen nicht zur Verfügung, wie z.B. Media Queries und Hover- / Focus-States. Wenn man mit Utility-CSS Klassen arbeitet, beschränkt man sich zudem bewusst auf ein bestimmtes Set an Klassen. Im Vergleich zu Inline-Syles bietet das den Vorteil, dass man durch diese Beschränkung automatisch konsistenter arbeitet.
Vorteile
- Endlose Diskussionen und Überlegungen darüber, wie bestimmte Klassen genannt werden, gehören der Vergangenheit an, denn CSS-Klassen müssen nicht semantisch benannt werden.
- Das Projekt-CSS wächst mit dem Projekt kaum an, da selbst wenn neue Komponenten dazu kommen, kaum zusätzliche CSS-Klassen verwendet werden müssen. Man hat recht schnell alles, was man braucht.
- Wird die letzte Instanz einer Utility CSS-Klasse gelöscht, kann auch das CSS an sich problemlos gelöscht werden (manuell oder automatisiert). In größeren Projekten ist das ansonsten kaum möglich, da oft viele undurchsichtige Abhängigkeiten entstehen.
- Dadurch, dass beim Utility-First Ansatz definiert werden muss, welche Utility-Klassen zur Verfügung stehen sollen, schränkt man sich automatisch auf ein Set von Design Tokens ein. Somit ist es deutlich leichter, ein konsistentes Design zu forcieren.
- Man sieht direkt im HTML wie das Element dargestellt wird.
Nachteile (auf dem Papier)
- Das HTML wird unvermeidbar "hässlicher", da man pro Element viele CSS Klassen hinzufügen muss.
- Man muss den klassischen Weg der vermeidlichen "Separation of Concerns" zwischen HTML und CSS verlassen (CSS Zen Garden etc.). Das CSS ist nicht mehr semantisch.
- Ein Build-Prozess ist nicht unbedingt nötig, um Utilitly-First CSS schreiben zu können, aber erst durch einen Build-Prozess kann man es in vollen Zügen genießen (Purging, Compiling, Autoprefixer etc.).
- Da man sich ansonsten recht schnell wiederholt, ist es sinnvoll, Komponenten-basiert zu arbeiten (React, Vue.js, Svelte etc.).
- Man nutzt einige Features von CSS nicht mehr (z.B. die Kaskade)
Tailwind CSS
Um das Utility-First CSS nicht jedes Mal selber schreiben zu müssen (da es im Prinzip ja immer das gleiche ist), bietet es sich an, dafür ein CSS-Framework zu nutzen. Für meine Website habe ich das sehr beliebte Tailwind CSS gewählt.
Tailwind ist ein Utility-First CSS Framework und funktioniert als PostCSS Plugin.
Neben der genial gewählten API (das System, wie die Klassen-Namen aufgebaut sind), besticht es zudem mit einem wirklich gut ausbalancierten Set an verfügbaren Klassen und deren Dokumentation.
Über eine Konfigurationsdatei lassen sich die Design Tokens, die dann verfügbar sind, definieren bzw. das Standard-Set anpassen.
Tailwind funktioniert dann so, dass im Production CSS Build nur die Klassen beinhaltet sind, die man in seinem Projekt verwendet hat.
In der Praxis arbeitet man also nur noch im HTML, bzw. in meinem Fall in den React-Komponenten.
Auch dynamisches Styling ist damit supereinfach, da es am Ende nur die Klassen-Namen sind, die man dynamisch zu seinen Elementen hinzufügen muss:
Fazit
Ich bin aktuell schwer begeistert. Diese Begeisterung kommt aus unterschiedlichen Gründen:
- Man ist uuuuultraschnell. Probiert es aus! Man kann sich vorher kaum vorstellen, wie viel Zeit man gewinnt, wenn man sich nicht mehr mit CSS-Klassen Namen und Strukturen beschäftigen muss. Bis jetzt sehe ich auch keinen Grund, wie einem das irgendwann auf die Füße fallen kann.
- Es fühlt sich alles so "stabil" an. Ohne Abhängigkeiten im CSS entfällt das klassische "Ich habe an Stelle X etwas geändert, warum geht jetzt Stelle Y kaputt". Das "Problem" beschränkt sich jetzt auf die Komponenten-Ebene, fühlt sich dort aber viel sinnvoller aufgehoben an.
- Der Nachteil "Kein Separation of Concerns" empfinde ich als Vorteil. Meiner Meinung nach war es vorher auch eher ein "Separation of Technologies". Die Möglichkeit, alles (Markup, Styling und Interaktivität) an einer Stelle in einer Datei zu haben, fühlt sich total gut an.
- Das CSS ist winzig. Mehr als 5 - 10 kB kommen selbst bei komplexen Projekten nicht zusammen (6,6 kB bei dieser Seite).
Wo würde ich Utility-First CSS bzw. Tailwind CSS aktuell einsetzen:
- Bei jeglichen "Production" Web-Projekten (Web-Sites und Web-Apps), die sowieso auf einen Build Prozess hinauslaufen.
Wo würde ich Utility-First CSS bzw. Tailwind CSS aktuell nicht einsetzten:
- Bei superkleinen, schnellen Themen, wo das Einbinden (und möglicherweise das Onboarding) länger dauert, als man durch die Nutzung gewinnt.
Wo bin ich mir noch nicht sicher:
- Aktuell experimentiere ich mit Design-Systemen bzw. Komponenten-Libraries mit React. Hier teste ich gerade, ob ein Tool wie Tailwind sinnvoll ist oder eine CSS-in-JS Lösung wie Stitches, Vanilla-Extract, Emotion, Styled Components o.Ä. eine bessere Lösung ist.
Stay tuned…