Eine Custom Property wird am häufigsten als Variable in CSS betrachtet.
.card {
--spacing: 1.2rem;
padding: var(--spacing);
margin-bottom: var(--spacing);
}
Oben ist --spacing die Custom Property mit dem Wert 1.2rem, und var(--spacing) ist die verwendete Variable.
Der vielleicht wertvollste Grund, sie zu verwenden: sich nicht zu wiederholen (DRY-Code). Im obigen Beispiel kann ich den Wert 1.2rem an einer Stelle ändern und damit zwei Dinge beeinflussen. Das bringt etwas aus Programmiersprachen in CSS.
Es gibt einiges über Custom Properties zu wissen, also legen wir los.
Warum sind CSS Custom Properties wichtig?
- Sie helfen, dein CSS zu entfeuchten (DRY = Don’t Repeat Yourself). Custom Properties können Code einfacher warten, da du einen Wert an einer Stelle aktualisieren kannst und dieser sich an mehreren Stellen widerspiegelt. Sei jedoch vorsichtig, denn übermäßige Abstraktion kann den gegenteiligen Effekt haben und den Code unverständlicher machen.
- Sie sind besonders hilfreich für Dinge wie die Erstellung von Farbthemen auf einer Website.
- Sie eröffnen interessante Möglichkeiten in CSS. Nicht zuletzt, weil sie kaskadieren.
- Die Tatsache, dass sie in JavaScript aktualisiert werden können, eröffnet noch interessantere Möglichkeiten.
Inhaltsverzeichnis
- Warum sind CSS Custom Properties wichtig?
- Benennung von Custom Properties
- Gültige Werte für Custom Properties
- Aufteilen von Werten
- Verwendung der Kaskade
- Kombination mit !important
- Fallback-Werte für Custom Properties
- Verwendung von calc() und Custom Properties
- @property
- Kommas in Werten
- Fortgeschrittene Verwendung
- Custom Properties und JavaScript
- Custom Properties unterscheiden sich von Präprozessor-Variablen
- Custom Properties und Web Components (Shadow DOM)
- Browser-Unterstützung
- Verwandte Beiträge
- Danksagung
Benennung von Custom Properties
Custom Properties müssen sich innerhalb eines Selektors befinden und mit zwei Bindestrichen (--) beginnen.
/* Nope, not within a selector */
--foo: 1;
body {
/* No, 0 or 1 dash won't work */
foo: 1;
-foo: 1;
/* Yep! */
--foo: 1;
/* OK, but they're different properties */
--FOO: 1;
--Foo: 1;
/* Totally fine */
--mainColor: red;
--main-color: red;
/* Special characters are a no */
--color@home: red;
--black&blue: black;
--black^2: black;
}
Es ist am besten, sich an Buchstaben, Zahlen und Bindestriche zu halten und sicherzustellen, dass die Custom Property innerhalb eines gültigen Selektors definiert ist.
Properties als Properties
Du kannst den Wert einer Custom Property mit einer anderen Custom Property festlegen.
html {
--red: #a24e34;
--green: #01f3e6;
--yellow: #f0e765;
--error: var(--red);
--errorBorder: 1px dashed var(--red);
--ok: var(--green);
--warning: var(--yellow);
}
Manche Leute machen das gerne so, weil es ermöglicht, dass der Name einer Custom Property beschreibend ist und dann in einer anderen Property mit einem funktionaleren Namen verwendet wird, was wiederum hilft, den Code DRY zu halten. Es kann sogar dazu beitragen, die funktionalen Namen lesbarer und verständlicher zu machen.
Es gibt einen großen Fallstrick bei Custom Properties, die andere Custom Properties verwenden, den du beachten solltest.
Gültige Werte für Custom Properties
Custom Properties sind überraschend tolerant, wenn es um die Werte geht, die sie akzeptieren.
Hier sind einige grundlegende Beispiele, von denen man erwarten würde, dass sie funktionieren, und das tun sie auch.
body {
--brand-color: #990000;
--transparent-black: rgba(0, 0, 0, 0.5);
--spacing: 0.66rem;
--max-reading-length: 70ch;
--brandAngle: 22deg;
--visibility: hidden;
--my-name: "Chris Coyier";
}
Siehst du? Es können Hex-Werte, Farbfunktionen, Einheiten aller Art und sogar Textzeichenfolgen sein.
Muster für die praktische Verwendung von CSS Custom Properties
Ein Strategie-Leitfaden für CSS Custom Properties
Vorteile von nativen CSS-Variablen
Custom Properties als Zustand
Aber Custom Properties müssen nicht unbedingt vollständige Werte wie diese sein. Schauen wir uns an, wie nützlich es sein kann, gültige CSS-Werte in Teile aufzuteilen, die wir in Custom Properties stecken können.
Aufteilen von Werten
Du kannst Custom Properties verwenden, um mehrteilige Werte aufzuteilen.
Stellen wir uns vor, du verwendest eine Farbfunktion, sagen wir rgba(). Jeder Farbkanalwert darin kann seine eigene Custom Property sein. Das eröffnet eine Menge Möglichkeiten, wie das Ändern des Alpha-Werts für einen bestimmten Anwendungsfall oder das Erstellen von Farbthemen.
Aufteilen von Farben
Nimm zum Beispiel HSL-Farben. Wir können sie in Teile aufteilen und dann die Teile, die wir wollen, sehr einfach anpassen. Vielleicht arbeiten wir mit der Hintergrundfarbe eines Buttons. Wir können bestimmte Teile seines HSL-Aufbaus aktualisieren, wenn der Button gehovert wird, fokussiert ist oder deaktiviert ist, ohne überhaupt background für einen dieser Zustände zu deklarieren.
button {
--h: 100;
--s: 50%;
--l: 50%;
--a: 1;
background: hsl(var(--h) var(--s) var(--l) / var(--a));
}
button:hover { /* Change the lightness on hover */
--l: 75%;
}
button:focus { /* Change the saturation on focus */
--s: 75%;
}
button[disabled] { /* Make look disabled */
--s: 0%;
--a: 0.5;
}
Indem wir Werte wie diesen aufteilen, können wir Teile davon steuern, auf eine Weise, wie wir es vorher nie konnten. Schau dir an, wie wir nicht alle HSL-Argumente deklarieren mussten, um den Hover-, Fokus- und Deaktivierungszustand eines Buttons zu stylen. Wir haben einfach spezifische HSL-Werte überschrieben, wenn wir sie brauchten. Ziemlich cool!
Schatten
box-shadow hat keine Shorthand-Eigenschaft, um die Ausdehnung des Schattens separat zu steuern. Aber wir könnten den box-shadow Ausdehnungswert herauslösen und ihn als Custom Property steuern (Demo).
button {
--spread: 5px;
box-shadow: 0 0 20px var(--spread) black;
}
button:hover {
--spread: 10px;
}
Verläufe
Es gibt keine background-gradient-angle (oder ähnliche) Shorthand für Farbverläufe. Mit Custom Properties können wir nur diesen Teil ändern, als gäbe es so etwas.
body {
--angle: 180deg;
background: linear-gradient(var(--angle), red, blue);
}
body.sideways {
--angle: 90deg;
}
Durch Kommas getrennte Werte (wie bei Hintergründen)
Jede Property, die mehrere durch Kommas getrennte Werte unterstützt, könnte ebenfalls ein guter Kandidat für das Aufteilen von Werten sein, da es keine Möglichkeit gibt, nur einen Wert aus einer durch Kommas getrennten Liste anzusprechen und ihn allein zu ändern.
/* Lots of backgrounds! */
background-image:
url(./img/angles-top-left.svg),
url(./img/angles-top-right.svg),
url(./img/angles-bottom-right.svg),
url(./img/angles-bottom-left.svg),
url(./img/bonus-background.svg);
Angenommen, du möchtest nur einen von vielen Hintergründen bei einer Media Query entfernen. Du könntest das mit Custom Properties so machen, was es zu einer trivialen Aufgabe macht, Hintergründe auszutauschen oder zu überschreiben.
body {
--bg1: url(./img/angles-top-left.svg);
--bg2: url(./img/angles-top-right.svg);
--bg3: url(./img/angles-bottom-right.svg);
--bg4: url(./img/angles-bottom-left.svg);
--bg5: url(./img/bonus-background.svg);
background-image: var(--bg1), var(--bg2), var(--bg3), var(--bg4);
}
@media (min-width: 1500px) {
body {
background-image: var(--bg1), var(--bg2), var(--bg3), var(--bg4), var(--bg5);
}
}
Grids
Wir sind gerade in Schwung, also machen wir noch ein paar Beispiele. Zum Beispiel können wir die Eigenschaft grid-template-columns nehmen und ihre Werte in Custom Properties abstrahieren, um ein super flexibles Grid-System zu erstellen.
.grid {
display: grid;
--edge: 10px;
grid-template-columns: var(--edge) 1fr var(--edge);
}
@media (min-width: 1000px) {
.grid {
--edge: 15%;
}
}
Transforms
CSS wird bald individuelle Transforms bekommen, aber wir können sie mit Custom Properties früher bekommen. Die Idee ist, alle Transforms, die ein Element erhalten könnte, im Voraus anzuwenden und sie dann bei Bedarf einzeln zu steuern.
button {
transform: var(--scale, scale(1)) var(--translate, translate(0));
}
button:active {
--translate: translate(0, 2px);
}
button:hover {
--scale: scale(0.9);
}
Verkettung von Einheitentypen
Es gibt Zeiten, in denen das Kombinieren von Teilen von Werten nicht so funktioniert, wie man es sich erhofft. Du kannst zum Beispiel nicht 24px erstellen, indem du 24 und px zusammenfügst. Das ist jedoch möglich, indem du die rohe Zahl mit einem Zahlenwert mit einer Einheit multiplizierst.
body {
--value: 24;
--unit: px;
/* Nope */
font-size: var(--value) + var(--unit);
/* Yep */
font-size: calc(var(--value) * 1px);
/* Yep */
--pixel_converter: 1px;
font-size: calc(var(--value) * var(--pixel_converter));
}
Kontextuelle Utility-Klassen für Farbe mit Custom Properties
Custom Properties (CSS-Variablen) dynamischer machen
Weitere CSS-Diagramme mit Grid & Custom Properties
Responsive Designs und CSS Custom Properties: Variablen und Breakpoints definieren
Der Stand der Änderung von Verläufen mit CSS-Transitions und Animationen
Verwenden von CSS Custom Properties zum Anpassen variabler Schriftstärken im Dark Mode
Verwendung der Kaskade
Die Tatsache, dass Custom Properties die Kaskade verwenden, ist eine ihrer nützlichsten Eigenschaften.
Du hast es bereits in vielen der Beispiele gesehen, die wir behandelt haben, aber lass es uns noch einmal verdeutlichen. Angenommen, wir haben eine Custom Property, die „sehr weit oben“ (am Body) festgelegt ist, und dann erneut für eine bestimmte Klasse festgelegt wird. Wir verwenden sie auf einer bestimmten Komponente.
body {
--background: white;
}
.sidebar {
--background: gray;
}
.module {
background: var(--background);
}
Dann haben wir praktisches HTML wie dieses:
<body> <!-- --background: white -->
<main>
<div class="module">
I will have a white background.
</div>
<main>
<aside class="sidebar"> <!-- --background: gray -->
<div class="module">
I will have a gray background.
</div>
</aside>
</body>

.sidebar ein näherer Vorfahre als body, daher löst --background dort zu gray auf, aber an anderen Stellen zu weiß.Das „Modul“ in der Sidebar hat einen grauen Hintergrund, weil Custom Properties (wie viele andere CSS-Eigenschaften) durch die HTML-Struktur vererbt werden. Jedes Modul nimmt den --background-Wert vom nächsten „Vorfahren“, bei dem er in CSS definiert wurde.
Wir haben also eine CSS-Deklaration, die in verschiedenen Kontexten unterschiedliche Dinge tut, dank der Kaskade. Das ist einfach cool.
Das spielt sich auch auf andere Weise ab:
button {
--foo: Default;
}
button:hover {
--foo: I win, when hovered;
/* This is a more specific selector, so re-setting
custom properties here will override those in `button` */
}
Media Queries ändern nicht die Spezifität, aber sie kommen oft später (oder weiter unten) in der CSS-Datei als der ursprüngliche Selektor, der einen Wert festlegt, was auch bedeutet, dass eine Custom Property innerhalb der Media Query überschrieben wird.
body {
--size: 16px;
font-size: var(--size);
}
@media (max-width: 600px) {
body {
--size: 14px;
}
}
Media Queries sind nicht nur für Bildschirmgrößen. Sie können für Dinge wie Barrierefreiheitseinstellungen verwendet werden. Zum Beispiel Dark Mode.
body {
--bg-color: white;
--text-color: black;
background-color: var(--bg-color);
color: var(--text-color);
}
/* If the user's preferred color scheme is dark */
@media screen and (prefers-color-scheme: dark) {
body {
--bg-color: black;
--text-color: white;
}
}
Die :root-Sache
Man sieht oft, dass Custom Properties „am Root“ festgelegt werden. Das bedeutet Folgendes:
:root {
--color: red;
}
/* ...is largely the same as writing: */
html {
--color: red;
}
/* ...except :root has higher specificity, so remember that! */
Es gibt keinen besonders zwingenden Grund, Custom Properties so zu definieren. Es ist einfach eine Möglichkeit, Custom Properties so weit oben wie möglich festzulegen. Wenn du das magst, ist das völlig in Ordnung. Ich finde es irgendwie normaler, sie auf die html- oder body-Selektoren anzuwenden, wenn ich Eigenschaften festlege, die ich global oder überall verfügbar machen möchte.
Es gibt auch keinen Grund, warum du Variablen in diesem breiten Geltungsbereich festlegen musst. Es kann genauso nützlich und vielleicht lesbarer und verständlicher sein, sie genau auf der Ebene festzulegen, auf der du sie verwenden wirst (oder ziemlich nah im DOM-Baum).
.module {
--module-spacing: 1rem;
--module-border-width: 2px;
border: var(--module-border-width) solid black;
}
.module + .module {
margin-top: var(--module-spacing);
}
Beachte, dass das Festlegen einer Custom Property am Modul selbst bedeutet, dass diese Property nicht mehr von einem Vorfahren erbt (es sei denn, wir setzen den Wert auf inherit). Wie bei anderen vererbten Eigenschaften gibt es manchmal Gründe, sie an Ort und Stelle (auf globaler Ebene) festzulegen, und manchmal möchten wir sie vom Kontext (auf Komponentenebene) erben. Beides ist nützlich. Das Coole an Custom Properties ist, dass wir sie an einer Stelle definieren, sie hinter den Kulissen vererben und sie an einer völlig anderen Stelle anwenden können. Wir übernehmen die Kontrolle über die Kaskade!
Ein Strategie-Leitfaden für CSS Custom Properties
Globale und Komponenteneinstellungen mit CSS-Variablen
CSS Custom Properties aus :root herauszulösen, könnte eine gute Idee sein
Kombination mit !important
Du kannst einen !important-Modifikator innerhalb oder außerhalb einer Variablen setzen.
.override-red {
/* this works */
--color: red !important;
color: var(--color);
/* this works, too */
--border: red;
border: 1px solid var(--border) !important;
}
Das Anwenden von !important auf die Variable --color macht es schwierig, den Wert der Variable --color zu überschreiben, aber wir können ihn immer noch ignorieren, indem wir die Eigenschaft color ändern.
Das Verhalten von !important innerhalb der Werte von Custom Properties ist ziemlich ungewöhnlich. Stefan Judis dokumentiert es gut, aber im Grunde:
- Letztendlich wird
!importantaus dem Wert der Custom Property entfernt. - Aber es wird verwendet, um zu bestimmen, welcher Wert gewinnt, wenn er an mehreren Stellen festgelegt wird.
div {
--color: red !important;
}
#id {
--color: yellow;
}
Wenn beide Selektoren auf ein Element angewendet werden, könnte man denken, dass der Wert von #id wegen der höheren Spezifität gewinnt, aber tatsächlich gewinnt red wegen des !important, wird aber letztendlich ohne das !important angewendet. Es ist etwas verwirrend.
Wenn man das !important außerhalb der Custom Property anwendet, wie im 2. Beispiel zwei Codeblöcke weiter oben, bleibt unsere --border-Variable von geringer Spezifität (leicht zu überschreiben), aber es ist schwierig, die Art und Weise zu ändern, wie dieser Wert auf den border selbst angewendet wird, da die gesamte Deklaration !important beibehält.
Fallback-Werte für Custom Properties
Die Funktion var() ermöglicht Fallback-Werte in Custom Properties.
Hier legen wir eine scale()-Transformationsfunktion für eine Custom Property fest, aber es gibt einen durch Kommas getrennten zweiten Wert von 1.2. Dieser Wert 1.2 wird verwendet, wenn --scale nicht festgelegt ist.
.bigger {
transform: scale(var(--scale, 1.2));
}
Nach dem ersten Komma sind alle weiteren Kommas Teil des Fallback-Werts. Das ermöglicht uns, Fallbacks mit durch Kommas getrennten Werten darin zu erstellen. Wir können zum Beispiel eine Variable haben, die auf einen ganzen Stapel von Schriftarten zurückfällt:
html {
font-family: var(--fonts, Helvetica, Arial, sans-serif);
}
Wir können auch eine Reihe von Variablen-Fallbacks bereitstellen (so viele wir wollen), aber wir müssen sie verschachteln, damit das funktioniert:
.bigger {
transform: scale(var(--scale, var(--second-fallback, 1.2));
}
Wenn --scale undefiniert ist, versuchen wir --second-fallback. Wenn auch das undefiniert ist, greifen wir schließlich auf 1.2 zurück.
Verwendung von calc() und Custom Properties
Noch mehr Leistung von Custom Properties wird freigeschaltet, wenn wir sie mit Mathematik kombinieren!
Diese Art von Dingen ist üblich:
main {
--spacing: 2rem;
}
.module {
padding: var(--spacing);
}
.module.tight {
/* divide the amount of spacing in half */
padding: calc(var(--spacing) / 2));
}
Wir könnten das auch verwenden, um den Farbton einer Komplementärfarbe zu berechnen:
html {
--brand-hue: 320deg;
--brand-color: hsl(var(--brand-hue), 50%, 50%);
--complement: hsl(calc(var(--brand-hue) + 180deg), 50%, 50%);
}
calc() kann sogar mit mehreren Custom Properties verwendet werden:
.slider {
width: calc(var(--number-of-boxes) * var(--width-of-box));
}
Verzögern des calc()
Es mag seltsam aussehen, eine kalkülähnliche Rechnung ohne ein calc() zu sehen:
body {
/* Valid, but the math isn't actually performed just yet ... */
--font-size: var(--base-font-size) * var(--modifier);
/* ... so this isn't going to work */
font-size: var(--font-size);
}
Der Trick ist, dass es funktioniert, solange du es schließlich in eine calc()-Funktion packst:
body {
--base-font-size: 16px;
--modifier: 2;
--font-size: var(--base-font-size) * var(--modifier);
/* The calc() is "deferred" down to here, which works */
font-size: calc(var(--font-size));
}
Dies könnte nützlich sein, wenn du ziemlich viel mit deinen Variablen rechnest und der calc()-Wrapper im Code ablenkend oder unübersichtlich wird.
@property
Die @property „at-rule“ in CSS ermöglicht es dir, den Typ einer Custom Property sowie ihren Anfangswert und ob sie vererbt wird, zu deklarieren.
Es ist, als würdest du eine tatsächliche CSS-Eigenschaft erstellen und hättest die Möglichkeit zu definieren, wie sie genannt wird, ihre Syntax, wie sie mit der Kaskade interagiert, und ihren Anfangswert.
@property --x {
syntax: '<number>';
inherits: false;
initial-value: 42;
}
Gültige Typen:
length (Länge)numberpercentage (Prozentwert)length-percentagecolorimage (Bild)urlintegerangle (Winkel)time (Zeit)resolutiontransform-listtransform-functioncustom-ident(eine benutzerdefinierte Bezeichnerzeichenfolge)
Das bedeutet, dass der Browser weiß, mit welcher Art von Wert er es zu tun hat, anstatt anzunehmen, dass alles eine Zeichenfolge ist. Das bedeutet, du kannst Dinge auf eine Weise animieren, wie du es sonst nicht könntest.
Angenommen, du hast ein sternförmiges Symbol, das du mit @keyframes drehen möchtest und mit einem transform rotieren möchtest. Also machst du das:
.star {
--r: 0deg;
transform: rotate(var(--r));
animation: spin 1s linear infinite;
}
@keyframes spin {
100% {
--r: 360deg;
}
}
Das funktioniert tatsächlich nicht, da der Browser nicht weiß, dass 0deg und 360deg gültige Winkelwerte sind. Du musst sie als Typ <angle> mit @property definieren, damit das funktioniert.
@property --r {
syntax: '<angle>';
initial-value: 0deg;
inherits: false;
}
.star {
--r: 0deg;
transform: rotate(var(--r));
animation: spin 1s linear infinite;
}
@keyframes spin {
100% {
--r: 360deg;
}
}
Demo
@property
Verwenden von @property für CSS Custom Properties
Erkundung von @property und seinen Animationsfähigkeiten
241: @property ist magisch
Kommas in Werten
Das kann ein bisschen verwirrend sein. Vielleicht nicht so sehr das hier:
html {
--list: 1, 2, 3;
}
Aber unten brauchst du ein scharfes Auge, um zu erkennen, dass der Fallback-Wert tatsächlich 1.2, 2 ist. Das erste Komma trennt den Fallback, aber der Rest ist Teil des Werts.
html {
transform: scale(var(--scale, 1.2, 2));
}
Erfahre mehr über Fallbacks oben ⮑
Fortgeschrittene Verwendung
The Raven ist eine Technik, die Container-Queries mithilfe von Mathematik und Custom Properties emuliert. Sei vorbereitet, das steigert die Komplexität sofort von 0 auf 100!
Demo
Ändere die Größe dieser Demo, um zu sehen, wie ein Raster von Inline-Block-Elementen die Spaltenanzahl von 4 auf 3 auf 1 ändert.
Hier sind noch ein paar weitere Lieblingsbeispiele, die die fortgeschrittene Verwendung von Custom Properties zeigen:
Custom Properties verwenden, um Variationen in Keyframe-Animationen zu beherrschen
Die Macht (und der Spaß) des Scopes mit CSS Custom Properties
So spielst und pausierst du CSS-Animationen mit CSS Custom Properties
Das Cicada-Prinzip, neu betrachtet mit CSS-Variablen
Der initial- und Leerzeichen-Trick
Denke an @media-Queries und wie du, wenn eine Sache sich ändert (z. B. die Breite der Seite), mehrere Dinge steuern kannst. Das ist ungefähr die Idee bei diesem Trick. Du änderst eine Custom Property und steuerst mehrere Dinge.
Der Trick ist, dass der Wert initial für eine Custom Property einen Fallback auslöst, während ein leerer Leerzeichenwert dies nicht tut. Zur Erklärung definieren wir zwei global gültige Custom Properties, ON und OFF:
:root {
--ON: initial;
--OFF: ;
}
Angenommen, wir haben eine „dark“-Variationsklasse, die eine Reihe verschiedener Eigenschaften festlegt. Der Standard ist --OFF, kann aber jederzeit auf --ON umgeschaltet werden:
.module {
--dark: var(--OFF);
}
.dark { /* could be a media query or whatever */
--dark: var(--ON);
}
Jetzt kannst du --dark verwenden, um bedingt Werte festzulegen, die nur angewendet werden, wenn du --dark auf --ON umgestellt hast. Demo
Lea Verou hat einen großartigen Artikel, der all dies abdeckt.
Inline-Styles
Es ist absolut zulässig, eine Custom Property in HTML mit einem Inline-Style festzulegen.
<div style="--color: red;"></div>
Das hat, wie jeder Inline-Style, eine sehr hohe Spezifität.
Dies kann super nützlich sein, wenn das HTML Zugriff auf nützliche Styling-Informationen hat, die zu seltsam/schwierig wären, um sie in eine statische CSS-Datei zu packen. Ein gutes Beispiel dafür ist die Beibehaltung des Seitenverhältnisses eines Elements:
<div style="--aspect-ratio: 16 / 9;"></div>
Jetzt kann ich CSS einrichten, um eine Box genau dieser Größe zu erstellen, wo immer ich sie brauche. Der vollständige Artikel dazu ist hier, aber hier ist CSS, das Tricks wie die „ol’ padded box“ auf ein Pseudoelement anwendet, das die Box auf die gewünschte Größe drückt:
[style*="--aspect-ratio"] > :first-child {
width: 100%;
}
[style*="--aspect-ratio"] > img {
height: auto;
}
@supports (--custom: property) {
[style*="--aspect-ratio"] {
position: relative;
}
[style*="--aspect-ratio"]::before {
content: "";
display: block;
padding-bottom: calc(100% / (var(--aspect-ratio)));
}
[style*="--aspect-ratio"] > :first-child {
position: absolute;
top: 0;
left: 0;
height: 100%;
}
}
Aber hey, heutzutage haben wir eine native aspect-ratio-Eigenschaft in CSS, daher könnte es in Zukunft sinnvoller sein, diese im Inline-Style festzulegen.
<div style="aspect-ratio: 16 / 9;"></div>
Hover und Pseudoelemente
Es gibt keine Möglichkeit, einen :hover-Style (oder andere Pseudoklassen/-elemente) mit Inline-Styles anzuwenden. Das heißt, es sei denn, wir tricksen mit Custom Properties. Angenommen, wir möchten benutzerdefinierte Hover-Farben für einige Boxen — wir können diese Informationen als Custom Property übergeben:
<div style="--hover-color: red;"><div>
<div style="--hover-color: blue;"><div>
<div style="--hover-color: yellow;"><div>
Und dann in CSS verwenden, das natürlich den Hover-Zustand eines Links stylen kann:
div:hover {
background-color: var(--hover-color);
}
/* And use in other pseudos! */
div:hover::after {
content: "I am " attr(style);
border-color: var(--hover-color);
}
Custom Properties und JavaScript
JavaScript kann den Wert einer Custom Property festlegen.
element.style.setProperty('--x', value);
Hier ist ein Beispiel für ein rotes Quadrat, das mit Custom Properties positioniert ist, und JavaScript aktualisiert diese Custom Property-Werte mit der Mausposition:
Normalerweise denkt man, dass JavaScript Werte an CSS übergibt, was wahrscheinlich 99 % der Nutzung ausmacht, aber beachte, dass du auch Dinge von CSS an JavaScript übergeben kannst. Wie wir gesehen haben, kann der Wert einer Custom Property ziemlich permissiv sein. Das bedeutet, du könntest ihm eine logische Anweisung übergeben. Zum Beispiel:
html {
--logic: if (x > 5) document.body.style.background = "blue";
}
Dann nimm diesen Wert und führe ihn in JavaScript aus:
const x = 10;
const logic = getComputedStyle(document.documentElement).getPropertyValue(
"--logic"
);
eval(logic);
Custom Properties unterscheiden sich von Präprozessor-Variablen
Angenommen, du verwendest bereits Sass, Less oder Stylus. All diese CSS-Präprozessoren bieten Variablen, und das ist einer der Hauptgründe, sie als Teil deines Build-Prozesses zu haben.
// Variable usage in Sass (SCSS)
$brandColor: red;
.marketing {
color: $brandColor;
}
Also, musst du dich dann überhaupt mit nativen CSS Custom Properties herumschlagen? Ja, solltest du. Hier ist der Grund in Kürze:
- Native CSS Custom Properties sind mächtiger als Präprozessor-Variablen. Ihre Integration in die Kaskade im DOM ist etwas, das Präprozessor-Variablen niemals tun können.
- Native CSS Custom Properties sind dynamisch. Wenn sie sich ändern (vielleicht über JavaScript oder mit einer Media Query), rendert der Browser neu, was er muss. Präprozessor-Variablen lösen sich beim Kompilieren in einen Wert auf und bleiben bei diesem Wert.
- Eine native Funktion zu verwenden, ist gut für die Langlebigkeit deines Codes. Du musst natives CSS nicht präprozessieren.
Ich behandle dies viel detaillierter in dem Artikel „Was ist der Unterschied zwischen CSS-Variablen und Präprozessor-Variablen?“
Um ganz ehrlich zu sein, gibt es kleine Dinge, die Präprozessor-Variablen tun können, die mit Custom Properties allein schwer oder unmöglich sind. Angenommen, du möchtest die Einheiten von einem Wert entfernen. Das kannst du in Sass tun, aber du wirst es mit Custom Properties in CSS allein viel schwerer haben.
Kann man Custom Properties präprozessieren?
Irgendwie. Du kannst dies tun, mit Sass, um nur einen beliebten Präprozessor zu nennen:
$brandColor: red;
body {
--brandColor: #{$brandColor};
}
Das tut nichts anderes, als eine Sass-Variable in eine Custom Property zu verschieben. Das könnte manchmal nützlich sein, aber nicht besonders. Sass wird dort einfach --brandColor: red; erstellen, nicht die Custom Property verarbeiten.
Wenn ein Browser Custom Properties nicht unterstützt, dann ist das so. Du kannst einen Browser nicht zwingen, das zu tun, was Custom Properties tun, allein durch CSS-Syntax-Transformationen. Es gäbe vielleicht ein JavaScript-Polyfill, das dein CSS parst und es nachbildet, aber ich schlage das wirklich nicht vor.
Das PostCSS Custom Properties-Plugin führt jedoch CSS-Syntax-Transformationen durch, um zu helfen. Was es tut, ist, den Wert nach bestem Wissen und Gewissen herauszufinden und diesen zusammen mit der Custom Property auszugeben. Zum Beispiel:
:root {
--brandColor: red;
}
body {
color: var(--brandColor);
}
Wird so ausgegeben:
:root {
--brandColor: red;
}
body {
color: red;
color: var(--brandColor);
}
Das bedeutet, dass du einen Wert erhältst, der in Browsern, denen die Unterstützung für Custom Properties fehlt, hoffentlich nicht fehlerhaft aussieht, aber keine der schicken Dinge unterstützt, die du mit Custom Properties machen kannst, und nicht einmal versucht, sie zu implementieren. Ich bin etwas skeptisch, wie nützlich das ist, aber ich denke, das ist ungefähr das Beste, was du tun kannst, und ich mag den Geist, zu versuchen, Dinge in älteren Browsern und neueren Browsern nicht kaputt zu machen.
Verfügbarkeit
Eine weitere Sache, die es wert ist, über den Unterschied zu sprechen, ist, dass bei einem CSS-Präprozessor die Variablen nur während des Verarbeitungsprozesses verfügbar sind. So etwas wie $brandColor ist in deinem HTML oder JavaScript bedeutungslos. Wenn du jedoch Custom Properties verwendest, kannst du Inline-Styles setzen, die diese Custom Properties verwenden, und sie werden funktionieren. Oder du kannst JavaScript verwenden, um ihre aktuellen Werte (im Kontext) herauszufinden, falls erforderlich.
Abgesehen von einigen etwas esoterischen Funktionen von Präprozessor-Variablen (z. B. einige mathematische Möglichkeiten) sind Custom Properties leistungsfähiger und nützlicher.
Custom Properties und Web Components (Shadow DOM)
Eine der gängigsten und praktischsten Möglichkeiten, Web Components zu stylen (z. B. eine <custom-component> mit Shadow DOM), ist die Verwendung von Custom Properties als Styling-Hooks.
Der Hauptzweck des Shadow DOM ist es, dass Stile nicht hinein oder heraus „durchsickern“, was eine Stil-Isolation bietet, die nichts anderes bietet, außer einem <iframe>. Stile kaskadieren jedoch immer noch hinein, ich kann nur nicht hineinselektieren. Das bedeutet, dass Custom Properties direkt hineingleiten werden.
Hier ist ein Beispiel:
Ein weiteres häufiges Vorkommen des Shadow DOM ist bei SVG und dem <use>-Element.
Video: „CSS Custom Properties dringen in das Shadow DOM ein“
Browser-Unterstützung
Diese Daten zur Browserunterstützung stammen von Caniuse, wo es mehr Details gibt. Eine Zahl gibt an, dass der Browser die Funktion ab dieser Version unterstützt.
Desktop
| Chrome | Firefox | IE | Edge | Safari |
|---|---|---|---|---|
| 49 | 31 | Nein | 16 | 10 |
Mobil / Tablet
| Android Chrome | Android Firefox | Android | iOS Safari |
|---|---|---|---|
| 127 | 127 | 127 | 10.0-10.2 |
Du kannst für tiefere Browser-Unterstützung präprozessieren, mit starken Einschränkungen.
@supports
Wenn du bedingtes CSS schreiben möchtest, wenn ein Browser Custom Properties unterstützt oder nicht:
@supports (--custom: property) {
/* Isolated CSS for browsers that DOES support custom properties, assuming it DOES support @supports */
}
@supports not (--custom: property) {
/* Isolated CSS for browsers that DON'T support custom properties, assuming it DOES support @supports */
}
Verwandte Beiträge
Danksagung
Vielen Dank an Miriam Suzanne für die Co-Autorschaft dieses Artikels!
Ich habe ein Polyfill für IE11 erstellt und finde es sehr praktisch, einfach ein Skript zu laden, trotz der Implikationen des Polyfills. In den meisten Fällen funktioniert es recht gut.
https://github.com/nuxodin/ie11CustomProperties
Vielen Dank an Chris und Miriam für diesen sehr gründlichen Leitfaden.
Eine Sache, die ich hinzufügen würde, ist, dass es heutzutage einige nützliche Funktionen in DevTools gibt, um auch bei Custom Properties zu helfen.
In Edge und Chrome zum Beispiel kannst du auf var()-Funktionen klicken, um direkt zu der Stelle zu springen, an der die in dieser Funktion verwendete Eigenschaft definiert ist.
Alle DevTools bieten auch den berechneten Wert als Tooltip beim Hover.
Tolle Zusammenstellung, viele Tipps und Tricks!
Kleiner Vorschlag: Ersetze „mousemove“ durch „pointermove“ im JavaScript-Beispiel, um auch Touch-Geräte einzubeziehen.
Ich sehe CSS-Variablen immer als „APIs“ für HTML und Web Components. Einfach zu verwenden, einfach über JS zu ändern, legt sogar Dinge von einer Komponente offen. Sie sind ein Segen in meinem Angular-Projekt bei $JOB.
Diese Grid-Trickserei ist aber so interessant.
Eine nützliche Sache, die du mit Präprozessor-Variablen und Custom Properties tun kannst, ist, eine Farbe automatisch in einen Haufen Custom Properties für Rot/Grün/Blau/Farbton/Sättigung/Helligkeit/Deckkraft umzuwandeln.
(außerdem musst du meiner Erfahrung nach Sass-Zeug explizit echoen, wenn du es in einer Custom Property verwendest, sonst wird es einfach als Zeichenfolge behandelt)
Und dann kannst du, wenn du möchtest, einfach eine Liste einfacher Farben als Sass-Variablen definieren, aber dann kannst du auch ganz einfach Farbvarianten erstellen. Wie dein Beispiel mit der Komplementärfarbe:
--complement: hsla(calc(var(--background-color-hue) + 180deg), var(--background-color-saturation), var(--background-color-lightness), var(--background-color-opacity));. Ich habe in meinen Projekten ein Mixin, das eine Map von Farben/Eigenschaftsnamen nimmt und sie so aufteilt.Toller Artikel!
Ich würde wahrscheinlich ein paar Anmerkungen zur Verwendung von CSS-Variablen innerhalb von :root und dem häufigen Fehler bei der Auswertung von Variablen hinzufügen.
Bsp.
Dann versuchen wir, die
--colorzu ändern, indem wir die anderen Variablen anpassen (z. B..container {--r:255;}), was nicht funktioniert.Eine verwandte SO-Frage: https://stackoverflow.com/a/52015817/8620333 (solche Fragen tauchen ziemlich oft auf)
TL;DR: Wir sollten Auswertungen innerhalb von :root immer vermeiden, wenn wir beabsichtigen, die Variable innerhalb verschiedener Elemente zu ändern.
Eine weitere Anmerkung zu „zyklischen Abhängigkeiten“ wäre ebenfalls hilfreich, da dies auch ein häufiger Fehler ist, wenn man versucht, Folgendes zu tun:
--p:calc(var(--p) + 1px), in dem Glauben, dass man die Variable inkrementieren kann, was ungültig ist.Eine letzte Anmerkung (nicht sehr wichtig): Auch wenn wir sie korrekt benennen sollten, ist es gut zu wissen, dass sie einige ungewöhnliche Syntaxen haben können. Wir können zum Beispiel nur die beiden Bindestriche verwenden
--:red. Natürlich keine gute Praxis, aber gut zu wissen. (verwandt: CSS variables can have strange syntaxes )Toller Artikel, aber es fehlt eine ziemlich große Sache: Du kannst Custom Properties nicht für Media Queries verwenden. Das hier funktioniert also nicht:
Das ist kein Fehler, sondern wahrscheinlich notwendig, um Endlosschleifen zu verhindern, wenn du z. B. den Wert von –tablet innerhalb der Media Query ändern würdest.
Aber du kannst SASS-Variablen für Media-Query-Breakpoints verwenden, und da dies immer noch eine sehr gängige und nützliche Sache ist, sollte der Vergleich zwischen SASS- und CSS-Variablen dies wahrscheinlich erwähnen.
Das hier funktioniert also gut, da $tablet beim Kompilieren in CSS durch 40em ersetzt wird:
Vielen Dank für diesen schönen Leitfaden, du bist ein Lebensretter :)
Ziemlich guter Beitrag!
Nur ein kleiner Fehler. Das angegebene Beispiel für Sass-Variable und Custom Property funktioniert nicht mehr. Das war früher richtig, aber jetzt sollte es so sein:
$brandColor: red;Körper {
--brandColor: #{$brandColor};
}
Weitere Details dazu hier https://github.com/sass/libsass/issues/2621
Schön, danke für den Hinweis!
Hallo,
Es gibt einige Konverter, die mir beim Übergang von CSS zu LESS zu SCSS geholfen haben. Sie bieten meistens die Möglichkeit, nach gängigen Eigenschaften zu suchen und daraus Variablen zu erstellen.
Jetzt möchte ich zurück zu Vanilla CSS mit Custom Properties. Ich suche ein Skript oder eine andere Lösung, um ein kompiliertes CSS (oder die ursprüngliche SCSS/LESS-Datei) einzugeben, und es konvertiert das CSS in eine Version, die Custom Properties verwendet.
Damit input.css:
oder input.scss:
in eine output.css konvertiert würde:
Ich habe viele Konverter gefunden, die das Gegenteil tun (z. B. PostCSS zum Konvertieren von Custom Properties in statisches „CSS3“-Style-CSS), aber nicht umgekehrt.
Ich habe nur einen Artikel gefunden, der in diese Richtung weist: https://codepen.io/jakealbaugh/post/css4-variables-and-sass
Und diese Diskussion konzentriert sich auf eine SASS-Lösung: Erstellen von CSS Custom Properties aus SCSS-Variablen.
Jetzt wende ich mich an meine letzte Hoffnung, CSS-Tricks. Kennt jemand da draußen ein automatisches oder halbautomatisches Konvertierungsskript?
Etwas spät, aber wahrscheinlich immer noch nützlich, Chatgpt kann das tun, wonach Sie meiner Meinung nach suchen.
Ich habe CSS von meiner Website eingegeben, an der ich gerade arbeite, wenn auch nur 100 Zeilen lang, und es hat das CSS nahezu perfekt modifiziert, indem es benutzerdefinierte Eigenschaften für alle Einträge hinzugefügt hat. Ich musste zwar einige Anpassungen vornehmen, aber der Großteil wurde automatisch für mich erledigt.