Das große Problem mit benutzerdefinierten Eigenschaften

Avatar of Chris Coyier
Chris Coyier am

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

Ich habe gesehen, dass dies in letzter Zeit mehr als eine Handvoll Leute verwirrt hat, mich eingeschlossen, also stelle ich sicher, dass es aufgeschrieben wird.

Lassen Sie uns ein paar benutzerdefinierte Eigenschaften in CSS einfügen

html {
  --color-1: red;
  --color-2: blue;
}

Lassen Sie uns sie sofort verwenden, um einen Hintergrundverlauf zu erstellen

html {
  --color-1: red;
  --color-2: blue;

  --bg: linear-gradient(to right, var(--color-1), var(--color-2));
}

Nehmen wir an, es gibt ein paar divs auf der Seite

<div></div>
<div class="variation"></div>

Lass sie uns gestalten

div {
  background: var(--bg);
}

Das funktioniert perfekt! Jawohl!

Nun lass mich diese Variante gestalten. Ich möchte nicht, dass sie von rot zu blau geht, ich möchte, dass sie von grün zu blau geht. Kinderleicht, ich ändere rot zu grün

html {
  --color-1: red;
  --color-2: blue;

  --bg: linear-gradient(to right, var(--color-1), var(--color-2));
}
div {
  background: var(--bg);
}
.variation {
  --color-1: green;
}

Nein! (Sirenen heulen, Hörner hupen, Nutztiere suchen Deckung).

Das funktioniert nicht, Freunde.

Das Problem, soweit ich es verstehe, ist, dass --bg niemals auf einem der divs deklariert wurde. Es kann --bg verwenden, da es weiter oben deklariert wurde, aber bis es dort verwendet wird, ist sein Wert gesperrt. Nur weil Sie eine andere Eigenschaft ändern, die --bg zufällig verwendet, als es deklariert wurde, bedeutet das nicht, dass diese Eigenschaft nach Orten sucht, an denen sie verwendet wurde, und alles aktualisiert, was sie als Abhängigkeit verwendet hat.

Ugh, diese Erklärung fühlt sich nicht ganz richtig an. Aber es ist das Beste, was ich habe.

Die Lösung? Nun, es gibt mehrere.

Lösung 1: Skalieren Sie die Variable auf den Ort, an dem Sie sie verwenden.

Sie könnten das tun

html {
  --color-1: red;
  --color-2: blue;
}

div {
  --bg: linear-gradient(to right, var(--color-1), var(--color-2));
  background: var(--bg);
}
.variant {
  --color-1: green;
}

Da --bg nun auf beiden divs deklariert ist, funktioniert die Änderung der --color-1 Abhängigkeit.

Lösung 2: Trennen Sie den Selektor, an dem Sie die meisten Variablen festlegen, mit Kommas.

Nehmen wir an, Sie machen das Übliche und legen eine Reihe von Variablen in :root fest. Dann stoßen Sie auf dieses Problem. Sie können einfach zusätzliche Selektoren zu dieser Hauptdeklaration hinzufügen, um sicherzustellen, dass Sie den richtigen Geltungsbereich treffen.

html,
div {
  --color-1: red;
  --color-2: blue;

  --bg: linear-gradient(to right, var(--color-1), var(--color-2));
}
div {
  background: var(--bg);
}
.variation {
  --color-1: green;
}

In einem anderen, vielleicht weniger konstruierten Beispiel könnte es so aussehen

:root, 
.button,
.whatever-it-is-a-bandaid {
  --padding-inline: 1rem;
  --padding-block: 1rem;
  --padding: var(--padding-block) var(--padding-inline);
}

.button {
  padding: var(--padding);
}
.button.less-wide {
  --padding-inline: 0.5rem;
}

Lösung 3: Blanket-Modus

Scheiß drauf – pack die Variablen überall hin.

* {
  --access: me;
  --whereever: you;
  --want: to;

  --hogwild: var(--access) var(--whereever);
}

Das ist keine gute Idee. Ich habe kürzlich eine Unterhaltung mitbekommen, bei der eine mittelgroße Website eine Verzögerung von 500 ms beim Rendern der Seite hatte, da jede Zeichenoperation auf der Seite alle Eigenschaften berechnen musste. Es „funktioniert“, aber es ist einer der seltenen Fälle, in denen Sie mit einem Selektor echte Leistungsprobleme verursachen können.

Lösung 4: Führen Sie eine neue „Standard“-Eigenschaft und einen Fallback ein

Die ganze Anerkennung hier geht an Stephen Shaw, dessen Erkundung all dessen einer der Orte ist, an denen ich diese Verwirrung überhaupt gesehen habe.

Kehren wir zu unserer ersten Demonstration dieses Problems zurück

html {
  --color-1: red;
  --color-2: blue;

  --bg: linear-gradient(to right, var(--color-1), var(--color-2));
}

Wir wollen uns zwei Dinge ermöglichen

  1. Eine Möglichkeit, den gesamten Hintergrund zu überschreiben
  2. Eine Möglichkeit, einen Teil des Farbverlauf-Hintergrunds zu überschreiben

Also werden wir es so machen

html {
  --color-1: red;
  --color-2: blue;
}
div {
  --bg-default: linear-gradient(to right, var(--color-1), var(--color-2));
  background: var(--bg, var(--bg-default));
}

Beachten Sie, dass wir --bg überhaupt nicht deklariert haben. Es liegt einfach da und wartet auf einen Wert, und wenn es jemals einen bekommt, ist das der Wert, der „gewinnt“. Aber ohne einen greift es auf unseren --bg-default zurück. Jetzt...

  1. Wenn ich --color-1 oder --color-2 einstelle, ersetzt es diesen Teil des Verlaufs wie erwartet (solange ich es auf einem Selektor tue, der eines der divs berührt).
  2. Oder ich kann --bg setzen, um den gesamten Hintergrund auf etwas zurückzusetzen, das ich möchte.

Fühlt sich wie eine schöne Art an, die Dinge zu handhaben.


Manchmal gibt es tatsächliche Fehler bei CSS-benutzerdefinierten Eigenschaften. Dies ist keiner davon. Auch wenn es sich für mich irgendwie wie ein Fehler anfühlt, ist es anscheinend keiner. Nur eines dieser Dinge, die man wissen muss.