Verwendung von CSS-Kaskadenebenen zur Verwaltung benutzerdefinierter Stile in einem Tailwind Projekt

Avatar of Ollie Williams
Ollie Williams am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

Wenn eine Hilfsklasse nur eine Sache tut, möchten Sie wahrscheinlich nicht, dass sie durch andere Stile überschrieben wird. Ein Ansatz ist die Verwendung von !important, um absolut sicher zu sein, dass der Stil angewendet wird, unabhängig von Spezifitätskonflikten.

Die Tailwind-Konfigurationsdatei verfügt über eine !important-Option, die automatisch !important zu jeder Hilfsklasse hinzufügt. Es ist nichts falsch daran, !important auf diese Weise zu verwenden, aber heutzutage gibt es bessere Möglichkeiten, mit Spezifität umzugehen. Mit CSS-Kaskadenebenen können wir den plumpen Ansatz von !important vermeiden.

Kaskadenebenen ermöglichen es uns, Stile in "Ebenen" zu gruppieren. Die Priorität einer Ebene schlägt immer die Spezifität eines Selektors. Spezifität spielt nur innerhalb jeder Ebene eine Rolle. Eine sinnvolle Ebenenreihenfolge hilft, Stilkonflikte und Spezifitätskämpfe zu vermeiden. Das macht CSS-Kaskadenebenen zu einem großartigen Werkzeug für die Verwaltung benutzerdefinierter Stile neben Stilen von Drittanbieter-Frameworks wie Tailwind.

Eine Tailwind-Quelldatei .css beginnt normalerweise so

@tailwind base;
@tailwind components;
@tailwind utilities;
@tailwind variants;

Werfen wir einen Blick auf die offizielle Tailwind-Dokumentation zu Direktiven

Direktiven sind benutzerdefinierte, Tailwind-spezifische @-Regeln, die Sie in Ihrem CSS verwenden können und die spezielle Funktionalität für Tailwind CSS-Projekte bieten. Verwenden Sie die Direktive @tailwind, um die base-, components-, utilities- und variants-Stile von Tailwind in Ihr CSS einzufügen.

In der Ausgabe-CSS-Datei, die erstellt wird, ist Tailwind's CSS-Reset – bekannt als Preflight – als Teil der Basisstile zuerst enthalten. Der Rest von base besteht aus CSS-Variablen, die Tailwind zum Arbeiten benötigt. components ist ein Ort, an dem Sie Ihre eigenen benutzerdefinierten Klassen hinzufügen können. Hilfsklassen, die Sie in Ihrem Markup verwendet haben, erscheinen als nächstes. Varianten sind Stile für Dinge wie Hover- und Fokuszustände und reaktionsfähige Stile, die zuletzt in der generierten CSS-Datei erscheinen.

Die Tailwind @layer-Direktive

Verwirrenderweise hat Tailwind eine eigene @layer-Syntax. Dieser Artikel handelt vom CSS-Standard, aber werfen wir einen kurzen Blick auf die Tailwind-Version (die kompiliert wird und nicht in der Ausgabe-CSS landet). Die Tailwind-@layer-Direktive ist eine Möglichkeit, Ihre eigenen zusätzlichen Stile in einen bestimmten Teil der Ausgabe-CSS-Datei einzufügen.

Zum Beispiel, um Ihre eigenen Stile an die base-Stile anzuhängen, würden Sie Folgendes tun

@layer base {
  h1 {
    font-size: 30px;
  }
}

Die components-Ebene ist standardmäßig leer – sie ist nur ein Ort, um Ihre eigenen Klassen zu platzieren. Wenn Sie die Dinge auf die Tailwind-Art tun würden, würden Sie wahrscheinlich @apply verwenden (obwohl der Ersteller von Tailwind kürzlich davon abgeraten hat), aber Sie können Klassen auch auf die normale Weise schreiben

@layer components {
  .btn-blue {
    background-color: blue;
    color: white;
  }
}

Der CSS-Standard ist viel mächtiger. Kommen wir dazu zurück...

Verwendung der CSS-Standard @layer

Hier ist, wie wir das umschreiben können, um die CSS-Standard @layer zu verwenden

@layer tailwind-base, my-custom-styles, tailwind-utilities;

@layer tailwind-base {
  @tailwind base;
}

@layer tailwind-utilities {
  @tailwind utilities;
  @tailwind variants;
} 

Im Gegensatz zur Tailwind-Direktive werden diese nicht kompiliert. Sie werden vom Browser verstanden. Tatsächlich zeigen DevTools in Edge, Chrome, Safari und Firefox sogar alle definierten Ebenen an.

CSS Cascade Layers with Tailwind CSS layers in DevTools.

Sie können beliebig viele Ebenen haben – und sie beliebig benennen – aber in diesem Beispiel sind alle meine benutzerdefinierten Stile in einer einzigen Ebene (my-custom-styles). Die erste Zeile legt die Ebenenreihenfolge fest

@layer tailwind-base, my-custom-styles, tailwind-utilities;

Dies muss im Voraus angegeben werden. Stellen Sie sicher, dass Sie diese Zeile vor jedem anderen Code einfügen, der @layer verwendet. Die erste Ebene in der Liste ist die *am wenigsten* mächtige, und die letzte Ebene in der Liste ist die *am mächtigsten*. Das bedeutet, tailwind-base ist die *am wenigsten mächtige* Ebene und jeder Code darin wird von allen nachfolgenden Ebenen überschrieben. Das bedeutet auch, dass tailwind-utilities immer alle anderen Stile übertrumpft – *unabhängig von der Quellreihenfolge oder Spezifität*. (Utilities und Varianten *könnten* in separaten Ebenen platziert werden, aber die Betreuer von Tailwind stellen sicher, dass Varianten immer über Utilities triumphieren, solange Sie die Varianten unter der Utilities-Direktive einfügen.)

Alles, was sich nicht in einer Ebene befindet, überschreibt alles, was sich in einer Ebene befindet (mit der einzigen Ausnahme von Stilen, die !important verwenden). Sie könnten also auch wählen, utilities und variants außerhalb jeder Ebene zu lassen

@layer tailwind-base, tailwind-components, my-custom-styles;

@layer tailwind-base {
  @tailwind base;
}

@layer tailwind-components {
  @tailwind components;
}

@tailwind utilities;
@tailwind variants;

Was hat uns das tatsächlich gebracht? Es gibt viele Fälle, in denen fortgeschrittene CSS-Selektoren sehr nützlich sind. Erstellen wir eine Version von :focus-within, die nur auf Tastaturfokus reagiert und nicht auf Mausklicks, indem wir den Selektor :has verwenden (der in Chrome 105 landet). Dies formatiert ein übergeordnetes Element, wenn eines seiner Kinder den Fokus erhält. Tailwind 3.1 hat benutzerdefinierte Varianten eingeführt – z. B. <div class="[&:has(:focus-visible)]:outline-red-600"> – aber manchmal ist es einfacher, einfach CSS zu schreiben

@layer tailwind-base, my-custom-styles;
@layer tailwind-base {
  @tailwind base;
}

@tailwind utilities;

@layer my-custom-styles {
  .radio-container {
    padding: 4px 24px;
    border: solid 2px rgb(230, 230, 230);
  }
  .radio-container:has(:focus-visible) {
    outline: solid 2px blue;
  }
}

Nehmen wir an, wir wollen nur in einem Fall die outline-color von blue in etwas anderes ändern. Nehmen wir an, das Element, mit dem wir arbeiten, hat sowohl die Tailwind-Klasse .outline-red-600 als auch unsere eigene Klasse .radio-container:has(:focus-visible)

<div class="outline-red-600 radio-container"> ... </div>

Welche outline-color wird gewinnen?

Normalerweise würde die höhere Spezifität von .radio-container:has(:focus-visible) bedeuten, dass die Tailwind-Klasse keine Wirkung hat – selbst wenn sie weiter unten in der Quellreihenfolge steht. Aber im Gegensatz zur Tailwind-@layer-Direktive, die auf der Quellreihenfolge basiert, überschreibt die CSS-Standard-@layer die Spezifität.

Daher können wir komplexe Selektoren in unseren eigenen benutzerdefinierten Stilen verwenden, sie aber bei Bedarf immer noch mit den Hilfsklassen von Tailwind überschreiben – ohne auf plumpes !important zurückgreifen zu müssen, um zu bekommen, was wir wollen.