Zum Inhalt springen
Abstrakte Formen aus Glas und dunklem Papier: eine Reihe kleiner Farbkacheln, verbunden mit einer daraus zusammengesetzten Form

Tailwind v4 Theme-Tokens: Brand-CSS-Variables sauber strukturieren

Tailwind v4 macht CSS-Variables zur ersten Klasse. Wie Sie Brand-Tokens für Farben, Spacing und Typography im @theme-Block organisieren, vererben und in komplexen Apps konsistent halten.

5 min Lesezeit Statamic

Warum Theme-Tokens

Vom Config-File zum CSS-First Token-System

Was sich mit Tailwind v4 ändert

In Tailwind 3 lebten alle Design-Tokens in einer JavaScript-Config. In v4 liegen Farben, Schriften, Spacing und Radien direkt als CSS-Variables im @theme-Block der Haupt-Stylesheet-Datei. Jede Variable wird automatisch zu einer Utility-Klasse, jede Utility ist gleichzeitig eine echte CSS-Variable. Das spart einen Build-Schritt und macht Ihre Tokens für Drittwerkzeuge, Storybook und Browser-DevTools sichtbar.

Was sich nicht ändert

Die Disziplin. Tokens sind nur dann ein System, wenn Sie sie hierarchisch denken: Primitive (rohe Werte), Semantik (Rolle im UI), Komponenten (Spezialfälle). Tailwind v4 nimmt Ihnen die Notation ab, aber nicht die Strategie.

Vorher

Die alte Welt: tailwind.config.js

Funktional, aber unsichtbar zur Laufzeit

Diese Config ist ein typisches Setup aus Tailwind 3. Funktioniert, ist aber zur Laufzeit verschwunden. DevTools zeigen Ihnen nur die compilierten Hex-Werte. Wer Werte aus dem Token-System lesen will, braucht den Build-Output. Custom Properties existieren nur, wenn Sie sie selbst duplizieren.

Das Doppelpflege-Problem

Sobald Sie Werte in eigenen CSS-Komponenten benutzen wollen (zum Beispiel in einer E-Mail-Vorlage oder in einem Web-Component), müssen Sie die Tokens zweimal pflegen: einmal in JS, einmal in CSS. Theme-Switching zur Laufzeit ist nur mit zusätzlichem Boilerplate möglich.

tailwind.config.js javascript
// Tailwind 3: alles in JS
module.exports = {
  theme: {
    extend: {
      colors: {
        brand: {
          50:  '#fff7ed',
          500: '#f97316',
          900: '#7c2d12',
        },
        ink: {
          900: '#0a0a0a',
          500: '#525252',
        },
      },
      fontFamily: {
        display: ['Inter Tight', 'sans-serif'],
        body:    ['Inter', 'sans-serif'],
      },
      spacing: {
        'gutter': '1.5rem',
        'section': '6rem',
      },
    },
  },
}

Nachher

Die neue Welt: @theme in app.css

Zwei @theme-Blöcke, zwei Ebenen

Wir splitten Primitives und Semantik in zwei separate @theme-Blöcke. Primitives sind Ihre rohen Brand-Farben in OKLCH (perzeptiv linear, vorhersehbare Kontraste). Semantische Tokens verweisen darauf und tragen Rollen wie „surface“ oder „accent“. In Templates verwenden Sie ausschließlich die semantischen Tokens.

Sub-Properties für Typography

Beachten Sie die --text-display-1--line-height Notation. Tailwind v4 erkennt diese Sub-Properties und gruppiert sie auf der Utility-Klasse text-display-1 mit. Eine einzige Utility, ein konsistentes Type-Set.

resources/css/app.css css
@import "tailwindcss";

@theme {
  /* Primitives: rohe Werte, niemals direkt in Templates verwenden */
  --color-brand-50:  oklch(97% 0.03 60);
  --color-brand-500: oklch(72% 0.18 50);
  --color-brand-900: oklch(36% 0.10 50);

  --color-ink-50:  oklch(98% 0 0);
  --color-ink-500: oklch(52% 0 0);
  --color-ink-900: oklch(15% 0 0);

  /* Typography */
  --font-display: "Inter Tight", sans-serif;
  --font-body:    "Inter", sans-serif;

  --text-display-1: 4rem;
  --text-display-1--line-height: 1.05;
  --text-display-1--letter-spacing: -0.02em;

  /* Spacing & Radius */
  --spacing-gutter:  1.5rem;
  --spacing-section: 6rem;
  --radius-card:     0.75rem;
}

/* Semantik: Rollen im UI, verweisen auf Primitives */
@theme {
  --color-surface:        var(--color-ink-50);
  --color-surface-strong: var(--color-ink-900);
  --color-accent:         var(--color-brand-500);
  --color-accent-hover:   var(--color-brand-900);
}
Ein Farbfächer: auf jedem Streifen eine Skala von hell bis dunkel, oben liegt der orange Streifen für den Akzent.

Naming-Konvention

Drei Ebenen, drei Präfix-Regeln

Primitives: Skala mit Zahlen

Verwendet eine konsistente Skala wie 50, 100, 200 bis 950. Auch wenn Sie nur drei Stufen brauchen, behalten Sie die Zahlen bei. So bleibt das Schema erweiterbar, ohne dass Sie später umbenennen müssen.

Semantik: Rolle, nicht Aussehen

Heißt „accent“ und nicht „orange“. Heißt „surface“ und nicht „white“. Wenn Ihr Marketing-Team das Brand-Orange in zwei Jahren auf Petrol umstellt, ändern Sie einen einzigen Wert in den Primitives.

Komponenten: Komponente vor Property

Für Komponenten-spezifische Tokens (etwa eine Button-Höhe) gilt „komponente-property“, also --button-height-md, nicht --md-button-height. Das macht Suchen, Auto-Complete und Refactoring deutlich angenehmer.

Token-Audit für Ihre App?

Wir prüfen Ihr Stylesheet auf Doppelpflege, Magic-Numbers und Inkonsistenzen.

Audit anfragen

Templates

Verwendung im Markup

Keine Primitives im Template

Das Template kennt nur semantische Utility-Klassen wie bg-surface und text-accent. Niemand schreibt bg-brand-500 in ein Template. Diese Regel halten Sie per Code-Review oder per Pint/Stylelint-Konvention durch.

Zur Laufzeit sichtbar

Im Browser können Sie im :root Inspector jede Variable lesen und ändern. Live-Theme-Tweaks im Kunden-Workshop. JavaScript greift mit getComputedStyle direkt auf die Werte zu, ohne Build-Tooling.

card.blade.php html
{{-- Templates verwenden ausschließlich semantische Utilities --}}
<article class="bg-surface text-surface-strong rounded-card p-gutter">
  <h2 class="font-display text-display-1">
    {{ $title }}
  </h2>

  <p class="font-body text-base text-ink-500">
    {{ $excerpt }}
  </p>

  <a href="{{ $url }}"
     class="text-accent hover:text-accent-hover">
    Weiterlesen
  </a>
</article>

Multi-Theme

Theme-Switching ohne JavaScript-Akrobatik

Sections-Wechsel statt prefers-color-scheme

Bei MARCODES wechseln wir helle und dunkle Sektionen im selben Layout. Statt einem globalen Dark-Mode-Schalter bekommt jede Sektion eine Klasse wie section-dark oder section-light, die intern andere semantische Tokens setzt. Ein @theme inline override pro Klasse, fertig.

Brand-Subbrands

Haben Sie Mandanten oder Subbrands? Setzen Sie ein data-brand Attribut am Root und definieren Sie pro Brand einen eigenen @theme inline Block. Ein Build, beliebig viele Themes, identische Utility-Namen im Template.

Stolperfallen

Was in der Praxis schiefgeht

Zu viele Primitives

Fünfzig Grautöne wirken professionell und sind in Wahrheit ein Wartungsalbtraum. Starten Sie mit drei bis fünf Stufen pro Farbgruppe. Mehr fügen Sie hinzu, wenn Sie im Design-Review einen konkreten Bedarf haben, nicht prophylaktisch.

Tokens als Aliase missbrauchen

Wenn --color-button-primary einfach nur --color-brand-500 heißt, ist es kein Token, sondern ein Alias. Tokens haben einen semantischen Wert oder sie gehören nicht ins System. Eine Komponente, die immer die Brand-Farbe nimmt, kann diese auch direkt referenzieren.

Magic-Numbers in Templates

Wer p-[17px] schreibt, baut das System aktiv kaputt. Tailwind v4 erlaubt arbitrary values, aber sie sollten in Code-Reviews die Ausnahme sein. Wenn Sie 17px wirklich brauchen, gehört der Wert in das Spacing-Token-System.

Hat das geholfen? Wir machen Audit, Workshop oder Coaching auch live.

Pakete direkt im Shop. Unser Standard-Tagessatz liegt bei 1.500 € netto.

Zum Shop