Muster für praktische CSS-Custom-Properties-Nutzung

Avatar of Tyler Childs
Tyler Childs am

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

Ich habe mit CSS Custom Properties experimentiert, um ihre Leistungsfähigkeit zu entdecken, da die Browserunterstützung endlich an einem Punkt ist, an dem wir sie in unserem Produktionscode verwenden können. Ich habe sie auf verschiedene Arten verwendet und würde mich freuen, wenn Sie sich genauso für sie begeistern würden wie ich. Sie sind so nützlich und leistungsfähig!

Ich finde, dass sich die Nutzung von CSS-Variablen in Kategorien einteilen lässt. Natürlich können Sie CSS-Variablen nach Belieben verwenden, aber das Denken in diesen verschiedenen Kategorien kann Ihnen helfen, die verschiedenen Arten zu verstehen, wie sie verwendet werden können.

  • Variablen. Die Grundlagen, wie z. B. die Festlegung einer Markenfarbe color, die überall dort verwendet werden kann, wo sie benötigt wird.
  • Standardwerte. Zum Beispiel ein Standard-border-radius, der später überschrieben werden kann.
  • Kaskadierende Werte. Verwendung von Hinweisen, die auf Spezifität basieren, wie z. B. Benutzereinstellungen.
  • Geltungsbereich von Regeln. Gezielte Variationen an einzelnen Elementen, wie Links und Schaltflächen.
  • Mixins. Regeln, die dazu bestimmt sind, ihre Werte in einen neuen Kontext zu bringen.
  • Inline-Eigenschaften. Werte, die aus Inline-Stilen in unserem HTML übergeben werden.

Die Beispiele, die wir uns ansehen, sind vereinfachte und komprimierte Muster aus einem CSS-Framework, das ich erstellt und pflege und das Cutestrap heißt.

Ein kurzer Hinweis zur Browserunterstützung

Es gibt zwei häufige Fragen, die ich höre, wenn Custom Properties zur Sprache kommen. Die erste betrifft die Browserunterstützung. Welche Browser unterstützen sie? Brauchen wir Fallbacks, wo sie nicht unterstützt werden?

Die globale Marktanteil, der die in diesem Beitrag behandelten Dinge unterstützt, beträgt 85 %. Dennoch lohnt es sich, caniuse mit Ihrer Benutzerbasis abzugleichen, um zu entscheiden, wie viel und wo progressive Enhancement für Ihr Projekt sinnvoll ist.

Die zweite Frage betrifft immer die Verwendung von Custom Properties. Tauchen wir also in die Nutzung ein!

Muster 1: Variablen

Als Erstes befassen wir uns mit der Festlegung einer Variablen für eine Markenfarbe als Custom Property und ihrer Verwendung in einem SVG-Element. Wir werden auch einen Fallback verwenden, um Benutzer in nachfolgenden Browsern abzudecken.

html {
  --brand-color: hsl(230, 80%, 60%);
}

.logo {
  fill: pink; /* fallback */
  fill: var(--brand-color);
}

Hier haben wir eine Variable namens --brand-color in unserer html-Regel deklariert. Die Variable ist auf einem Element definiert, das immer vorhanden ist, sodass sie in jedes Element kaskadiert, in dem sie verwendet wird. Kurz gesagt, wir können diese Variable in unserer .logo-Regel verwenden.

Wir haben einen pink Fallback-Wert für nachfolgende Browser deklariert. In der zweiten `fill`-Deklaration übergeben wir --brand-color in die var()-Funktion, die den von uns für diese Custom Property festgelegten Wert zurückgibt.

Das ist im Grunde das Muster: Definieren Sie die Variable (--variable-name) und verwenden Sie sie dann in einem Element (var(--variable-name)).

Siehe den Pen
Muster für praktische Custom Properties: Beispiel 1.0
von Tyler Childs (@tylerchilds)
auf CodePen.

Muster 2: Standardwerte

Die var()-Funktion, die wir im ersten Beispiel verwendet haben, kann auch Standardwerte liefern, falls die Custom Property, auf die sie zugreifen möchte, nicht gesetzt ist.

Nehmen wir zum Beispiel an, wir geben Buttons einen abgerundeten Rand. Wir können eine Variable erstellen – wir nennen sie --roundness –, aber wir definieren sie nicht, wie wir es zuvor getan haben. Stattdessen weisen wir beim Verwenden der Variable einen Standardwert zu.

.button {
  /* --roundness: 2px; */
  border-radius: var(--roundness, 10px);
}

Ein Anwendungsfall für Standardwerte ohne Definition der Custom Property ist, wenn Ihr Projekt noch im Design ist, aber Ihr Feature heute fällig ist. Dies erleichtert die spätere Aktualisierung des Wertes, wenn sich das Design ändert.

Sie geben Ihrem Button also einen schönen Standardwert, erfüllen die Frist und wenn --roundness schließlich als globale Custom Property festgelegt wird, erhält Ihr Button dieses Update kostenlos, ohne dass Sie darauf zurückkommen müssen.

Siehe den Pen
Muster für praktische Custom Properties: Beispiel 2.0
von Tyler Childs (@tylerchilds)
auf CodePen.

Sie können auf CodePen bearbeiten und den obigen Code auskommentieren, um zu sehen, wie der Button aussehen wird, wenn --roundness gesetzt ist!

Muster 3: Kaskadierende Werte

Nachdem wir die Grundlagen beherzigen, wollen wir die Zukunft aufbauen, die wir uns selbst schulden. Ich vermisse die Persönlichkeit, die AIM und MySpace hatten, indem sie es den Benutzern ermöglichten, sich mit benutzerdefinierten Text- und Hintergrundfarben auf Profilen auszudrücken.

Lassen Sie uns das wiederbeleben und ein Schulnachrichtenbrett bauen, bei dem jeder Schüler seine eigene Schriftart, Hintergrundfarbe und Textfarbe für die von ihm geposteten Nachrichten festlegen kann.

Benutzerbasierte Themes

Was wir im Grunde tun, ist, dass Schüler ein benutzerdefiniertes Theme erstellen können. Wir werden die Theme-Konfigurationen innerhalb von Data-Attribute-Regeln festlegen, sodass alle Nachkommen – in diesem Fall ein .message-Element –, die die Themes konsumieren, Zugriff auf diese Custom Properties haben.

.message {
  background-color: var(--student-background, #fff);
  color: var(--student-color, #000);
  font-family: var(--student-font, "Times New Roman", serif);
  margin-bottom: 10px;
  padding: 10px;
}

[data-student-theme="rachel"] {
  --student-background: rgb(43, 25, 61);
  --student-color: rgb(252, 249, 249);
  --student-font: Arial, sans-serif;
}

[data-student-theme="jen"] {
  --student-background: #d55349;
  --student-color: #000;
  --student-font: Avenir, Helvetica, sans-serif;
}

[data-student-theme="tyler"] {
  --student-background: blue;
  --student-color: yellow;
  --student-font: "Comic Sans MS", "Comic Sans", cursive;
}

Hier ist die Markierung

<section>
  <div data-student-theme="chris">
    <p class="message">Chris: I've spoken at events and given workshops all over the world at conferences.</p>
  </div>
  <div data-student-theme="rachel">
    <p class="message">Rachel: I prefer email over other forms of communication.</p>
  </div>
  <div data-student-theme="jen">
    <p class="message">Jen: This is why I immediately set up my new team with Slack for real-time chat.</p>
  </div>
  <div data-student-theme="tyler">
    <p class="message">Tyler: I miss AIM and MySpace, but this message board is okay.</p>
  </div>
</section>

Wir haben alle unsere Schüler-Themes mit [data-student-theme]-Selektoren für unsere Schüler-Theme-Regeln festgelegt. Die Custom Properties für background, color und font gelten für unsere .message-Regel, wenn sie für diesen Schüler gesetzt sind, da .message ein Nachkomme des Divs ist, das das Data-Attribut enthält, welches wiederum die Custom Property-Werte zum Konsumieren enthält. Andernfalls werden stattdessen die von uns bereitgestellten Standardwerte verwendet.

Siehe den Pen
Muster für praktische Custom Properties: Beispiel 3.0
von Tyler Childs (@tylerchilds)
auf CodePen.

Lesbares Theme-Override

So lustig und cool es auch ist, wenn Benutzer benutzerdefinierte Stile steuern, was Benutzer auswählen, wird nicht immer unter Berücksichtigung von Kontrast, Farbfehlsichtigkeit oder jedem, der lieber nicht sieht, dass seine Augen beim Lesen bluten, zugänglich sein. Erinnern Sie sich an die GeoCities-Zeiten?

Fügen wir eine Klasse hinzu, die ein saubereres Aussehen und Gefühl bietet, und wenden wir sie auf das übergeordnete Element (<section>) an, damit sie jedes Schülerthema überschreibt, wenn es vorhanden ist.

.readable-theme [data-student-theme] {
  --student-background: hsl(50, 50%, 90%);
  --student-color: hsl(200, 50%, 10%);
  --student-font: Verdana, Geneva, sans-serif;
}
<section class="readable-theme">
  ...
</section>

Wir nutzen die Kaskade, um die Schülerthemen zu überschreiben, indem wir eine höhere Spezifität festlegen, sodass Hintergrund, Farbe und Schriftart im Geltungsbereich liegen und auf jede .message-Regel angewendet werden.

Siehe den Pen
Muster für praktische Custom Properties: Beispiel 3.1
von Tyler Childs (@tylerchilds)
auf CodePen.

Muster 4: Geltungsbereich von Regeln

Apropos Geltungsbereich: Wir können Custom Properties in einem Geltungsbereich definieren und sie verwenden, um ansonsten redundanten CSS-Code zu optimieren. Zum Beispiel können wir Variablen für verschiedene Linkzustände definieren.

a {
  --link: hsl(230, 60%, 50%);
  --link-visited: hsl(290, 60%, 50%);
  --link-hover: hsl(230, 80%, 60%);
  --link-active: hsl(350, 60%, 50%);
}

a:link {
  color: var(--link);
}

a:visited {
  color: var(--link-visited);
}

a:hover {
  color: var(--link-hover);
}

a:active {
  color: var(--link-active);
}
<a href="#">Link Example</a>

Nachdem wir die Custom Properties global auf dem <a>-Element aufgeschrieben und sie in unseren Linkzuständen verwendet haben, müssen wir sie nicht noch einmal schreiben. Diese sind auf die Regel unseres <a>-Elements beschränkt, sodass sie nur auf Anker-Tags und deren Nachkommen angewendet werden. Dies ermöglicht es uns, den globalen Namensraum nicht zu verschmutzen.

Beispiel: Graustufen-Link

Zukünftig können wir die von uns erstellten Links steuern, indem wir die Custom Properties für unsere verschiedenen Anwendungsfälle ändern. Erstellen wir zum Beispiel einen grauen Link.

.grayscale {
  --link: LightSlateGrey;
  --link-visited: Silver;
  --link-hover: DimGray;
  --link-active: LightSteelBlue;
}
<a href="#" class="grayscale">Link Example</a>

Wir haben eine .grayscale-Regel deklariert, die die Farben für unsere verschiedenen Linkzustände enthält. Da der Selektor dieser Regel eine höhere Spezifität als die Standardeinstellung hat, werden diese Variablenwerte verwendet und dann auf die Pseudoklassen-Regeln für unsere Linkzustände angewendet, anstatt auf die auf dem <a>-Element definierten.

Siehe den Pen
Muster für praktische Custom Properties: Beispiel 4.0
von Tyler Childs (@tylerchilds)
auf CodePen.

Beispiel: Benutzerdefinierte Links

Wenn das Festlegen von vier Custom Properties zu viel Arbeit zu sein scheint, was ist, wenn wir stattdessen einen einzelnen Farbton festlegen? Das könnte die Verwaltung erheblich vereinfachen.

.custom-link {
  --hue: 30;
  --link: hsl(var(--hue), 60%, 50%);
  --link-visited: hsl(calc(var(--hue) + 60), 60%, 50%);
  --link-hover: hsl(var(--hue), 80%, 60%);
  --link-active: hsl(calc(var(--hue) + 120), 60%, 50%);
}

.danger {
  --hue: 350;
}
<a href="#" class="custom-link">Link Example</a>
<a href="#" class="custom-link danger">Link Example</a>

Siehe den Pen
Muster für praktische Custom Properties: Beispiel 4.1
von Tyler Childs (@tylerchilds)
auf CodePen.

Indem wir eine Variable für einen Farbton einführen und sie auf unsere HSL-Farbwerte in den anderen Variablen anwenden, müssen wir nur diesen einen Wert ändern, um alle vier Linkzustände zu aktualisieren.

Berechnungen sind in Kombination mit Custom Properties leistungsfähig, da sie es ermöglichen
Ihre Stile mit weniger Aufwand ausdrucksstärker zu gestalten. Schauen Sie sich diese Technik an von Josh Bader, wo er einen ähnlichen Ansatz verwendet, um zugängliche Farbkontraste bei Schaltflächen zu erzwingen.

Muster 5: Mixins

Ein Mixin in Bezug auf Custom Properties ist eine Funktion, die als Wert einer Custom Property deklariert wird. Die Argumente für den Mixin sind andere Custom Properties, die den Mixin neu berechnen, wenn sie geändert werden, was wiederum die Stile aktualisiert.

Das benutzerdefinierte Link-Beispiel, das wir uns gerade angesehen haben, ist tatsächlich ein Mixin. Wir können den Wert für --hue festlegen, und dann werden alle vier Linkzustände entsprechend neu berechnet.

Beispiel: Basisraster-Grundlage

Lernen wir mehr über Mixins, indem wir ein Basisraster erstellen, das beim vertikalen Rhythmus hilft. So hat unser Inhalt einen angenehmen Takt, indem er konsistente Abstände nutzt.

.baseline,
.baseline * {
  --rhythm: 2rem;
  --line-height: var(--sub-rhythm, var(--rhythm));
  --line-height-ratio: 1.4;
  --font-size: calc(var(--line-height) / var(--line-height-ratio));
}

.baseline {
  font-size: var(--font-size);
  line-height: var(--line-height);
}

Wir haben die Regeln für unser Basisraster auf eine .baseline-Klasse und alle ihre Nachkommen angewendet.

  • --rhythm: Dies ist die Grundlage unseres Rhythmus. Eine Änderung wirkt sich auf alle anderen Eigenschaften aus.
  • --line-height: Dies ist standardmäßig auf --rhythm gesetzt, da --sub-rhythm hier nicht gesetzt ist.
  • --sub-rhythm: Dies ermöglicht es uns, die --line-height – und damit die --font-size – zu überschreiben und gleichzeitig das gesamte Basisraster beizubehalten.
  • --line-height-ratio: Dies hilft, einen guten Zeilenabstand zu gewährleisten.
  • --font-size: Dies wird berechnet, indem unsere --line-height durch unser --line-height-ratio geteilt wird.

Wir haben auch unsere font-size und line-height in unserer .baseline-Regel so festgelegt, dass sie --font-size und --line-height aus unserem Basisraster verwenden. Kurz gesagt, wann immer sich der Rhythmus ändert, ändern sich auch Zeilenhöhe und Schriftgröße entsprechend, während ein lesbares Erlebnis erhalten bleibt.

OK, bringen wir das Basisraster zur Anwendung.

Erstellen wir eine winzige Webseite. Wir verwenden unsere --rhythm Custom Property für alle Abstände zwischen den Elementen.

.baseline h2,
.baseline p,
.baseline ul {
  padding: 0 var(--rhythm);
  margin: 0 0 var(--rhythm);
}

.baseline p {
  --line-height-ratio: 1.2;
}

.baseline h2 {
  --sub-rhythm: calc(3 * var(--rhythm));
  --line-height-ratio: 1;
}

.baseline p,
.baseline h2 {
  font-size: var(--font-size);
  line-height: var(--line-height);
}

.baseline ul {
  margin-left: var(--rhythm);
}
<section class="baseline">
  <h2>A Tiny Webpage</h2>
  <p>This is the tiniest webpage. It has three noteworthy features:</p>
  <ul>
    <li>Tiny</li>
    <li>Exemplary</li>
    <li>Identifies as Hufflepuff</li>
  </ul>
</section>

Wir verwenden hier im Wesentlichen zwei Mixins: --line-height und --font-size. Wir müssen die Eigenschaften font-size und line-height auf ihre entsprechenden Custom Property-Pendants setzen, um die Überschrift und den Absatz festzulegen. Die Mixins wurden in diesen Regeln neu berechnet, müssen aber gesetzt werden, bevor die aktualisierten Stile darauf angewendet werden.

Siehe den Pen
Muster für praktische Custom Properties: Beispiel 5.0
von Tyler Childs (@tylerchilds)
auf CodePen.

Etwas zu beachten: Sie wollen die Custom Property-Werte wahrscheinlich nicht in der Regel selbst verwenden, wenn Sie Mixins mit einem Platzhalter-Selektor anwenden. Dies verleiht diesen Stilen eine höhere Spezifität als jeder andere Erbe, der durch die Kaskade entsteht, was es schwierig macht, sie ohne Verwendung von !important zu überschreiben.

Muster 6: Inline-Eigenschaften

Wir können Custom Properties auch inline deklarieren. Lassen Sie uns ein leichtgewichtiges Grid-System bauen, um dies zu demonstrieren.

.grid {
  --columns: auto-fit;

  display: grid;
  gap: 10px;
  grid-template-columns: repeat(var(--columns), minmax(0, 1fr));
}
<div class="grid">
  <img src="https://www.fillmurray.com/900/600" alt="Bill Murray" />
  <img src="https://www.placecage.com/900/600" alt="Nic Cage" />
  <img src="https://www.placecage.com/g/900/600" alt="Nic Cage gray" />
  <img src="https://www.fillmurray.com/g/900/600" alt="Bill Murray gray" />
  <img src="https://www.placecage.com/c/900/600" alt="Nic Cage crazy" />
  <img src="https://www.placecage.com/gif/900/600" alt="Nic Cage gif" />
</div>

Standardmäßig hat das Raster gleich große Spalten, die sich automatisch zu einer einzigen Zeile anordnen.

Siehe den Pen
Muster für praktische Custom Properties: Beispiel 6.0
von Tyler Childs (@tylerchilds)
auf CodePen.

Um die Anzahl der Spalten zu steuern, können wir unsere --columns Custom Property setzen
inline auf unserem Grid-Element.

<div class="grid" style="--columns: 3;">
  ...
</div>

Siehe den Pen
Muster für praktische Custom Properties: Beispiel 6.1
von Tyler Childs (@tylerchilds)
auf CodePen.


Wir haben gerade sechs verschiedene Anwendungsfälle für Custom Properties betrachtet – zumindest solche, die ich häufig verwende. Selbst wenn Sie Custom Properties bereits kannten und verwendet haben, hoffe ich, dass die Betrachtung ihrer Verwendung auf diese Weise Ihnen eine bessere Vorstellung davon gibt, wann und wo Sie sie effektiv einsetzen können.

Gibt es verschiedene Arten von Mustern, die Sie mit Custom Properties verwenden? Teilen Sie sie in den Kommentaren und verlinken Sie einige Demos – ich würde sie gerne sehen!

Wenn Sie neu bei Custom Properties sind und Ihre Fähigkeiten verbessern möchten, probieren Sie die hier behandelten Beispiele aus, aber fügen Sie Medienabfragen hinzu. Sie werden sehen, wie anpassungsfähig diese sein können und wie viele interessante Möglichkeiten sich eröffnen, wenn Sie die Möglichkeit haben, Werte unterwegs zu ändern.

Außerdem gibt es eine Menge anderer großartiger Ressourcen direkt hier auf CSS-Tricks, um Ihre Fähigkeiten im Bereich Custom Properties im Custom Properties Guide zu verbessern.

Siehe den Pen
Danke fürs Lesen!
von Tyler Childs (@tylerchilds)
auf CodePen.