Zum Hauptinhalt springen
  1. Posts/

Tailwind nach 20 Jahren CSS-Vermeidung: warum ausgerechnet jetzt

·5 min
Autor
Detlev Lengsfeld
Seit Jahrzehnten im Unix-Subsystem zu Hause. Entwickler, Systemadministrator und Liebhaber puristischer Terminal-Workflows.
Mein Stack ist seit Jahren derselbe: statische Sites, Markup in der Hand, CSS in ein paar hundert Zeilen Plain mit Custom-Properties. Drei Anläufe mit CSS-Frameworks sind gescheitert. Warum der vierte geblieben ist.

Vorgeschichte: 20 Jahre kein CSS-Framework — und warum
#

Frameworks habe ich konsequent gemieden, nicht aus Prinzip, sondern aus Erfahrung: jede Abhängigkeit ist eine Verbindlichkeit, jeder Build-Step ein potentieller Ausfall, jedes Update ein potentieller Bruch. Drei haben es bis zu echten Projekten geschafft, dann wieder rausgeflogen. Der vierte Versuch — Tailwind — ist geblieben. Das ist die Geschichte dahinter, und vor allem das Reasoning, warum.

Drei Anläufe, die nicht hängengeblieben sind
#

  1. ~2005

    YAML CSS

    Webstandard-Schule

    Float-basiert, semantisches HTML, Accessibility-fokussiert. Aus der deutschen Webstandard-Tradition. Funktionierte hervorragend — bis Smartphones Mobile-First zur Pflicht machten und float-Layouts ihre Grenze fanden.
  2. ~2012

    Bootstrap

    Mobile-First-Wende

    Grid-System, Mobile-First, riesiges Ökosystem. Funktioniert. Aber jede Bootstrap-Site sieht aus wie eine Bootstrap-Site. Eigene Designs entstehen nur über Sass-Overrides oder Custom-CSS neben Bootstrap — der Stack verdoppelt sich.
  3. ~2018

    Bulma

    Flexbox-Modernisierung

    Sauberer als Bootstrap, kein JavaScript-Zwang. Aber das Grundproblem blieb: Component-First-Modell. `
  4. 2024

    Tailwind

    Paradigmen-Bruch

    Utility-First statt Component-First. Geblieben.

Alle drei Anläufe sind in eigenen Projekten gestrandet. Nicht aus Inkompetenz der Frameworks, sondern weil das Modell — vorgefertigte Komponenten als Primitive — nicht zu der Arbeitsweise passt, die ich brauche.

Note

Zum Hintergrund von YAML CSS: Das Framework von Dirk Jesse war im DACH-Raum lange ein Standardwerk für barrierearmes Webdesign. Wer Mitte der 2000er semantisches HTML mit Layout-Anspruch wollte, kam an YAML schwer vorbei. Heute historisch interessant, aber technisch tot.

Der Paradigmen-Bruch: Utility-First statt Component-First
#

Der eigentliche Unterschied von Tailwind ist nicht technisch, sondern konzeptionell. Klassen wie .button sind Abstraktionen über Designs, die sich ändern. Utility-Klassen wie bg-zinc-900 px-4 py-2 rounded sind Abstraktionen über CSS-Properties, die sich nicht ändern.

Das ist der Kern. Ein Button ist immer Padding plus Hintergrund plus Border-Radius. Welcher Hintergrund, wie viel Padding, welcher Radius — das ist Design-Entscheidung pro Projekt. Component-First zementiert diese Entscheidung in der Klasse. Utility-First belässt sie da, wo sie hingehört: am konkreten Element.

Für wen das fremd klingt: https://www.ngo-online.de/2024/06/20/was-ist-tailwind-css/ erklärt die Tailwind-Grundlagen kompakt und ohne Marketing-Speak. Für dieses Posting reicht der konzeptionelle Punkt: Tailwind ist nicht “Bootstrap mit anderen Klassennamen”, sondern ein anderes Modell.

Was am Anfang nach “Inline-CSS mit Extra-Schritten” aussieht, entpuppt sich nach ein paar Wochen Arbeit als das Gegenteil. Die Klassen sind nicht beliebig, sondern aus einem konsistenten Design-Token-System (Spacing-Skala, Farb-Skala, Breakpoint-Skala). Du schreibst nicht margin: 17px, du schreibst mt-4 — und der gesamte Codebase nutzt dieselbe Skala. Das ist eher Design-System-Disziplin als Inline-Chaos.

Was mich tatsächlich überzeugt hat
#

JIT-Compilation. In Tailwind v3 ist das Standard: der Compiler scannt den Source-Tree, erkennt welche Utility-Klassen tatsächlich verwendet werden, und generiert nur diese ins Stylesheet. Mein Output-CSS für diese Site liegt deutlich unter 20 KB — Plain-CSS mit Custom-Properties war ungefähr gleich groß, aber ohne die Mächtigkeit eines kompletten Utility-Systems.

@apply als Notausgang. Wenn Utility-Sequenzen wirklich zu lang werden — etwa ein wiederkehrendes Button-Pattern an dreißig Stellen — kannst du in einer einzigen CSS-Datei eine echte Komponente definieren:

.btn-primary {
  @apply bg-zinc-900 text-white px-4 py-2 rounded hover:bg-zinc-700;
}
Tip

@apply ist der pragmatische Mittelweg: Utility-First als Default, Component-First wo es sich lohnt. Das ist die ehrliche Antwort auf die “HTML wird zu laut”-Kritik — und kein Ausstieg aus dem Tailwind-Modell, sondern bewusster Trade-off pro wiederkehrendem Pattern.

Das @tailwindcss/typography-Plugin. Für eine Doku- oder Blog-Site ist das Gold wert. Eine einzige Klasse prose am Markdown-Container, und Headings, Listen, Code-Blöcke, Tabellen, Links sehen typografisch sauber aus — ohne 200 Zeilen article h2 { ... } selbst zu pflegen.

Important

Für ein Projekt wie diese Site, das primär aus Markdown-Posts besteht, ist das typography-Plugin der eigentliche Hebel. Ohne es wäre der Migrations-Aufwand gegenüber Plain-CSS deutlich höher gewesen — mit ihm war die Entscheidung schon nach dem ersten Render-Vergleich gefallen.

Wo Tailwind nervt: ehrliche Kritik
#

Tailwind ist kein Allheilmittel. Drei Dinge, die mich stören:

HTML wird visuell laut. Eine typische Card sieht so aus: <div class="flex flex-col gap-4 rounded-lg bg-zinc-800 p-6 shadow-md hover:shadow-lg transition">. Editor-Wrap hilft, @apply hilft, aber der Code-Geruch bleibt. Wer großen Wert auf “sauberes HTML” legt, wird damit nicht warm.

Lernkurve ist Memorize-Arbeit. Du musst die Klassennamen lernen. mt-4 ist nicht margin: 4px, sondern margin-top: 1rem. gap-2 ist nicht 2 Pixel, sondern 0.5rem. Das ist intellektuell nicht anspruchsvoll, aber kostet die ersten zwei Wochen Aufmerksamkeit. Cheat-Sheet immer offen.

Warning

Ohne Build-Pipeline geht nichts. Für statische HTML-Seiten ohne Build-Step ist Tailwind die falsche Wahl. Du brauchst PostCSS, einen Watcher, einen JIT-Compiler. Bei einer Hugo-Site mit hugo --minify ist das integriert — bei einer Plain-HTML-Site müsstest du Pipeline-Infrastruktur dazubauen, die du sonst nicht brauchst. Tailwind belohnt Sites mit Build und bestraft Sites ohne.

Mein konkretes Setup
#

Diese Site läuft auf Hugo mit dem blowfish-Theme, das selbst auf Tailwind aufsetzt. Das war keine bewusste Tailwind-Entscheidung, sondern Konsequenz der Theme-Wahl — aber genau deshalb ein guter Praxis-Test: Theme-Defaults nutzen, nur dort eingreifen, wo es nötig ist.

tailwind.config.js minimal erweitert:

module.exports = {
  content: ['./layouts/**/*.html', './content/**/*.md'],
  theme: {
    extend: {
      fontFamily: {
        sans: ['Inter', 'system-ui', 'sans-serif'],
        mono: ['JetBrains Mono', 'ui-monospace', 'monospace'],
      },
    },
  },
  plugins: [require('@tailwindcss/typography')],
}

Build-Integration läuft über Hugo Pipes — kein separates Webpack, kein Gulp, kein npm-run-Skript-Karneval:

hugo --minify

Das war’s. Ein Befehl produziert das komplette Static-Output, inklusive PostCSS-Verarbeitung der Tailwind-Source. Deploy danach per rsync auf den Server. Die ganze Pipeline ist in einem zwanzigzeiligen Shell-Script, das auch das Sitemap-Ping und die Cache-Invalidierung übernimmt.

Wichtigster Punkt: ich musste null Custom-Klassen für Markdown-Output schreiben. Das prose-Plugin macht den Job. Das ist die konkrete Reibungsersparnis, die meine Skepsis überstimmt hat.

Fazit: Pragmatismus schlägt Purismus
#

Reduktion ist eine Tugend, aber kein Selbstzweck. Wenn ein Werkzeug die Reibung im Workflow tatsächlich reduziert, ohne den Stack zu vergiften — wenig Dependencies, klare Buildschritte, transparente Output-Größe —, ist die Adoption rational, nicht idiomatisch.

Tailwind erfüllt diese Bedingungen. Bootstrap und Bulma haben es nicht getan, YAML konnte es zu seiner Zeit nicht. Der Unterschied liegt nicht in “Tailwind ist neuer”, sondern im Modell. Utility-First ist näher an dem, wie sich Plain-CSS anfühlt, wenn man es lange genug ohne Framework macht — nur mit System.

Für die nächste Site werde ich es wieder so machen.