CSS mit modernen Werkzeugen besser strukturieren

the next big thing Golo Roden  –  24 Kommentare

CSS ist die dritte große Sprache der Webentwicklung, neben HTML und JavaScript. Im Gegensatz zu diesen beiden wird CSS allerdings von vielen Entwicklerinnen und Entwicklern eher stiefmütterlich behandelt. Woran liegt das? Und sind die Gründe für modernes CSS noch relevant?

Verschiedene Technologien betonen unterschiedliche Schwerpunkte. React beispielsweise führt mit JSX eine eigene Erweiterung für JavaScript ein, um HTML nahtlos in JavaScript einbetten zu können. Vue.js hingegen integriert JavaScript eher in HTML, indem es proprietäre HTML-Attribute einführt, um JavaScript an HTML anbinden zu können.

Was bei dieser Betrachtung allerdings in beiden Fällen zu kurz kommt, ist CSS als dritte große Sprache der Webentwicklung. Tatsächlich ist CSS bei vielen Entwicklerinnen und Entwicklern eher unbeliebt, zumal es sich bei CSS eher um ein Werkzeug für das Design und weniger für die Entwicklung handelt. Aus der Sicht der Entwicklung wirkt CSS häufig wenig intuitiv und fehleranfällig, zudem gibt es bedingt durch verschiedene Webbrowser und Geräte gelegentlich auch unerwartete Unterschiede in der Darstellung.

Außerdem tendiert CSS dazu, rasch unübersichtlich zu werden, wofür es mehrere Gründe gibt. Zum einen fehlen klar in der Sprache definierte Regeln, wie CSS zu strukturieren ist. Zum anderen ist CSS per Definition global, weshalb es häufig unerwünschte Seiteneffekte gibt, die zu Konflikten zwischen eigentlich unabhängigen Komponenten führen.

Das Ziel der modernen Webentwicklung muss daher sein, CSS möglichst lokal und isoliert zu verwenden, sodass Seiteneffekte keinen Einfluss außerhalb des gewünschten Bereichs nehmen können. Der dafür einfachste Ansatz ist der Einsatz von Inline-CSS, indem jedes zu gestaltende Element mit einem style-Attribut versehen wird. Das löst das zuvor benannte Problem insofern, als sich ein style-Attribut stets nur auf das Element bezieht, auf dem es definiert wird.

Allerdings weist dieser Ansatz auch zahlreiche Nachteile auf. Mit style-Attributen lassen sich nämlich nicht alle Elemente gestalten, beispielsweise werden Pseudo-Elemente wie hover nicht unterstützt. Außerdem ist es auf dem Weg nicht möglich, responsive Komponenten zu gestalten, da Media-Queries ebenfalls nicht unterstützt werden. Auch die fehlende Wiederverwendbarkeit, fehlendes (automatisches) Vendor-Prefixing und die Unmöglichkeit, derartig geschriebenes CSS effizient zu cachen, fallen negativ ins Gewicht.

CSS inline definieren

CSS-Modules verwenden

Die Herausforderung besteht also darin, CSS tatsächlich lokal und isoliert definieren zu können, ohne aber an Mächtigkeit, Einfachheit, Komfort, Struktur und Effizienz Nachteile hinnehmen zu müssen. Das alles lässt sich mit einem relativ neuen Ansatzes erreichen, mit sogenannten CSS-Modules. Dabei handelt es sich um reguläre CSS-Dateien, die allerdings nur lokalen Einfluss haben.

Allerdings geht es dabei nicht um ein Features des Webbrowsers, sondern es wird ein (in der Regel JavaScript-basiertes) Build-Werkzeug wie webpack benötigt. Der Ansatz ist dabei relativ simpel. Statt die CSS-Datei nämlich über HTML zu laden, wird sie in den JavaScript-Code importiert, als würde es sich dabei um ein reguläres JavaScript-Modul handeln. Da das technisch nicht ohne weiteres möglich ist, braucht man für diesen Schritt besagtes Build-Werkzeug.

Beim Import werden nun die in der CSS-Datei hinterlegten Klassennamen durch generierte eindeutige IDs ersetzt, auf die man dann im JavaScript-Code Zugriff hat. Damit kann eine Entwicklerin oder ein Entwickler in der Komponentendefinition mit lesbaren Klassennamen arbeiten, zur Laufzeit ist aber garantiert, dass die Klassennamen eindeutig und somit lokal sind. Konflikte kann es auf dem Weg nicht mehr geben.

Da in den CSS-Dateien alle Möglichkeiten von CSS zur Verfügung stehen, lassen sich auch Pseudo-Elemente und Media-Queries verwenden, zudem können diese Dateien bei Bedarf auch weiterhin mit SASS, SCSS oder einem anderen Preprozessor verarbeitet werden. Außerdem funktioniert der Ansatz sogar mit alten Webbrowsern wie dem Internet Explorer, da es sich eben nicht um eine Funktion des Webbrowsers selbst handelt.

Sogar Themes lassen sich mit CSS-Modules umsetzen. Hierfür müssen lediglich CSS-Variablen definiert werden, auf die dann in den CSS-Modules zurückgegriffen werden kann. Leider liegt genau hier der Haken: Der Internet Explorer unterstützt CSS-Variablen nämlich nicht, weshalb Themes in Verbindung mit CSS-Modules nur in modernen Webbrowsern funktionieren. Falls man den Internet Explorer ignorieren kann, sind CSS-Modules also das Mittel der Wahl, falls nicht, hat man ein Problem, sofern man Themes unterstützen möchte.

CSS-Modules verwenden

Themes in CSS

Bevor man sich nun anschickt, eine technische Lösung für dieses Problem zu finden, gilt es zunächst, Themes besser zu verstehen. Generell dienen Themes dazu, zwei Ziele zu erreichen: Zum einen sollen sie die Auswahl an Größen, Abständen, Farben & Co. limitieren, zum anderen sollen sie verschiedene Designs umsetzen, zwischen denen Anwenderinnen und Anwender gegebenenfalls wechseln können. Die einfachste und vermutlich gängigste Variante ist dabei die Unterstützung eines Light- und eines Dark-Modus.

Tatsächlich gibt es bei Themes aber weitaus mehr Optionen, so können Themes nochmals über Varianten verfügen, die jeweils wiederum in einer Light- und einer Dark-Variante vorliegen. Hier sind also beliebig komplexe Szenarien denkbar.

Inhaltlich ist es sinnvoll, die technischen und fachlichen Aspekte eines Themes zu trennen. Die technischen Aspekte sind dabei die grundlegenden Werte, die für den Einsatz in Komponenten zur Verfügung stehen. Dazu gehören, wie bereits erwähnt, unter anderem Größen, Abstände und Farben. Es bietet sich an, den zur Auswahl stehenden Werten sprechende Namen zuzuweisen, beispielsweise small, medium und large, und die tatsächlich gewählten Werte auf dem Weg von der Intention zu entkoppeln.

In Komponenten wird dann stets nur noch auf diese Begriffe referenziert. Es entsteht also eine Indirektion, indem zum Beispiel festgelegt wird, dass der Titel eines Artikels in der Schriftgröße medium angezeigt werden soll. Auf dem Weg lässt sich die Schriftgröße für Artikeltitel zentral ändern, ohne andere Schriftgrößen zu beeinflussen. Trotzdem besteht zusätzlich die Option, allgemein und komponentenübergreifend zu ändern, was unter der Schriftgröße medium zu verstehen ist.

Um diese Indirektion umzusetzen, empfiehlt es sich, ein Theme inhaltlich in zwei Bereiche zu zerlegen: Der erste befasst sich ausschließlich mit den technischen Aspekten, also den grundlegenden Werten, der zweite mit der Abbildung dieser Werte auf die Komponenten. Selbstverständlich mag es in einigen Fällen begründete Ausnahmen geben, warum Größen, Abstände & Co. doch direkt in einer Komponente definiert werden sollen, dann weicht deren Definition aber auch bewusst von den Definitionen aller anderen Komponenten ab.

Themes in CSS

Styled Components

Um Themes und CSS im Allgemeinen nun zu definieren, benötigt man nach wie vor einen Ansatz, der die eingangs erwähnten Herausforderungen vereint und integriert. Zu diesem Zweck gibt es für React das Modul styled-components, das über npm installiert werden kann. Im Wesentlichen exportiert das Modul eine Funktion namens styled, mit deren Hilfe man HTML-Elemente und die gewünschten CSS-Angaben zu einer gemeinsamen Komponente verbinden kann.

Auf dem Weg ist man als Entwicklerin oder Entwickler gezwungen, jedem gestalteten Element einen eigenen fachlichen Namen zu geben, sodass man nicht (wie häufig bei klassischem CSS) mit zahllosen div-Elementen hantieren muss, sondern von vornherein eine fachliche Struktur aufbauen kann. Da die Definition der Stile direkt in JavaScript erfolgt, entfällt beim Einsatz von styled-components die Notwendigkeit, selbst Klassennamen zu vergeben. Unter der Haube passiert das natürlich weiterhin, in der Entwicklung ist das aber vollkommen transparent.

Das Modul unterstützt dabei alle Fähigkeiten von CSS, einschließlich Pseudo-Elementen und Media-Queries. Es kümmert sich außerdem automatisch um Vendor-Prefixing und unterstützt das Definieren von Themes von Haus aus, so dass man sich hierfür keinen gesonderten Weg überlegen muss. Zu guter Letzt können CSS-Angaben sogar über Variablen aus JavaScript parametrisiert werden, was styled-components ausgesprochen flexibel und zugleich mächtig macht. Dass das Modul auch mit TypeScript hervorragend harmoniert, ist ein weiterer Pluspunkt.

Styled Components

Modernes CSS

Es fällt auf, dass weder CSS-Modules noch styled-components den Einsatz eines Vorgehens wie BEM oder OOCSS erfordern, da das CSS in beiden Fällen von Vornherein nur noch lokal auf Komponentenebene definiert wird. Diese Strukturmaßnahmen haben also in der modernen Webentwicklung letztlich ausgedient und sind daher nicht mehr relevant – oder zumindest weitaus weniger relevant als noch vor einigen Jahren.

Zugleich sinkt auch die Relevanz von SASS, SCSS und ähnlichen Preprozessoren. LESS beispielsweise hatte laut Google Trends seinen Höhepunkt bereits im Jahr 2015, SASS 2017. Seitdem geht die Nutzung dieser Technologien stetig zurück. Abgelöst werden diese Technologien durch CSS, das in JavaScript integriert wird, was auch als "CSS in JS" bekannt ist, und was auch von zahlreichen JSS-Frameworks vorangetrieben wird.

Eine Sache hat sich aber allen technischen Neuerungen zum Trotz nicht verändert: Es ist nach wie vor essenziell wichtig, die fachlichen und technischen Aspekte von CSS sauber trennen zu können, wie im Abschnitt über Themes beschrieben. Nur wenn das gelingt ist man auch in der Lage, skalierbares CSS zu schreiben, das auch in großen und komplexen Anwendungen mit Themes funktioniert.

Modernes CSS

Fazit

Modernes CSS kommt Entwicklerinnen und Entwicklern sehr entgegen. Vorbei sind die Zeiten, in denen man sich mit zahllosen Werkzeugen und Preprozessoren beschäftigen musste. Eine einziges einfaches Modul wie styled-components genügt inzwischen völlig, um hervorragend strukturiertes CSS schreiben zu können, das in allen gängigen Webbrowsern funktioniert, alle Funktionen von CSS unterstützt, einfach und komfortabel zu verwenden ist und dabei lesbar und verständlich bleibt.

Sofern man auf die Unterstützung des Internet Explorer verzichten kann, benötigt man sogar noch nicht einmal ein eigenständiges Modul, sondern kann CSS-Modules einsetzen, die von einigen Laufzeitumgebungen wie beispielsweise Next.js bereits von Haus aus unterstützt werden. Es ist anzunehmen, dass derartigen Ansätzen die Zukunft im Webdesign und in der Webentwicklung gehört.