typisierte Custom Properties — animierbar und validiert
CSS Custom Properties sind mächtig, aber untypisiert — der Browser behandelt sie als reine Strings. CSS @property ändert das grundlegend: Mit Typ-Deklaration, Vererbungskontrolle und initialem Wert werden Custom Properties zu vollwertigen, animierbaren CSS-Werten. Gradienten, Farben und Zahlen lassen sich damit interpolieren und mit Transitions verbinden.
Inhaltsverzeichnis
- 1. Was @property löst
- 2. Der syntax-Descriptor: Typen für Custom Properties
- 3. inherits — Vererbungskontrolle
- 4. initial-value — sichere Fallback-Werte
- 5. Animierbarkeit: Custom Properties interpolieren
- 6. Gradienten mit @property animieren
- 7. Zahlen-Properties für CSS-Counter und Layout
- 8. CSS.registerProperty() in JavaScript
- 9. @property vs. untypisierte Custom Properties
- 10. Zusammenfassung
- 11. FAQ
1. Was @property löst
CSS Custom Properties – bekannt als CSS-Variablen – sind seit 2017 in allen Browsern verfügbar und haben das Styling von Designsystemen revolutioniert. Sie haben jedoch eine fundamentale Einschränkung: Der Browser behandelt sie als typenlose Strings. Das bedeutet, dass Transitions und Animationen auf Custom Properties nicht funktionieren – der Browser weiß nicht, wie er zwischen --color: #ff0000 und --color: #0000ff interpolieren soll, weil er nicht weiß, dass es sich um Farbwerte handelt. Mit CSS @property gibt man dem Browser diese Information explizit.
Die @property-Regel ist Teil der CSS Houdini APIs – einer Sammlung von Low-Level-Browser-APIs, die Entwicklern Zugriff auf den CSS-Engine-Kern geben. @property ist davon das zugänglichste und praktischste Feature, das heute ohne experimentelle Flags in allen modernen Browsern verfügbar ist. Neben der Animierbarkeit löst @property auch das Problem der Validierung: Der Browser lehnt ungültige Werte ab und fällt auf den deklarierten initial-value zurück, statt einen fehlerhaften String durchzulassen. Das macht Design-Token-Systeme deutlich robuster.
Ein dritter Vorteil von @property betrifft die Vererbungskontrolle. Normale Custom Properties werden im DOM immer vererbt – ein Wert, der auf body gesetzt wird, gilt für alle Kindelemente, außer er wird explizit überschrieben. Mit inherits: false in einer @property-Deklaration kann man das unterbinden. Das ist besonders nützlich für Animationswerte, die lokal an eine Komponente gebunden sein sollen und nicht versehentlich durch Elternselektion beeinflussbar sein dürfen.
2. Der syntax-Descriptor: Typen für Custom Properties
Der syntax-Descriptor in einer @property-Deklaration definiert den Typ des Custom Property. Die unterstützten Typen umfassen <color>, <length>, <number>, <percentage>, <angle>, <time>, <resolution>, <transform-list>, <custom-ident> und <image>. Kombinationen sind mit Leerzeichen (für Sequenzen) und | (für Alternativen) möglich. Der universelle Typ * entspricht dem untypisierten Verhalten normaler Custom Properties und deaktiviert die Validierung.
Der syntax-Typ bestimmt, wie der Browser den Wert interpretiert und ob eine Interpolation möglich ist. Nur Typen, die numerische oder farbliche Werte repräsentieren, können interpoliert werden – das sind <color>, <length>, <number>, <percentage>, <angle> und kombinierte Typen wie <length-percentage>. String-Typen wie <custom-ident> können nicht interpoliert werden, profitieren aber von der Validierung. Die präzise Typangabe in @property ist der entscheidende Schritt, der Custom Properties von String-Platzhaltern zu echten CSS-Werten macht.
/* Typed Custom Properties with @property */
/* Color type: enables color interpolation in transitions */
@property --brand-color {
syntax: '<color>';
inherits: false;
initial-value: #7c3aed;
}
/* Number type: enables numeric interpolation */
@property --progress {
syntax: '<number>';
inherits: false;
initial-value: 0;
}
/* Percentage type: for layout-related animations */
@property --fill-level {
syntax: '<percentage>';
inherits: true;
initial-value: 0%;
}
/* Angle type: for rotation animations */
@property --rotation {
syntax: '<angle>';
inherits: false;
initial-value: 0deg;
}
/* Length: for custom spacing animations */
@property --offset-x {
syntax: '<length>';
inherits: false;
initial-value: 0px;
}
/* Usage — transitions now work on the custom property */
.card {
background-color: var(--brand-color);
transition: --brand-color 0.4s ease;
}
.card:hover {
--brand-color: #4a1d96;
}
3. inherits — Vererbungskontrolle
Das inherits-Feld in einer @property-Deklaration ist ein boolescher Wert (true oder false) und bestimmt, ob der Wert des Custom Property im DOM-Baum nach unten vererbt wird. Normale CSS Custom Properties erben immer. Mit @property und inherits: false wird das Custom Property lokal – es gilt nur für das Element, auf dem es direkt gesetzt wird, und nicht für dessen Kindelemente.
In der Praxis ist inherits: false besonders nützlich für Animations- und Transitions-Werte, die an eine spezifische Komponente gebunden sein sollen. Wenn man beispielsweise eine Hover-Animation mit einem --hover-progress-Property implementiert, soll dieses Property nicht von Elternelementen auf Kindelemente durchsickern – sonst könnten unerwünschte Animationseffekte entstehen. inherits: true hingegen eignet sich für Design-Tokens wie Markenfarben, die im gesamten Teilbaum konsistent sein sollen.
4. initial-value — sichere Fallback-Werte
Der initial-value-Descriptor definiert den Standardwert des Custom Property, der verwendet wird, wenn das Property nicht explizit gesetzt wurde oder ein ungültiger Wert angegeben wurde. Das ist eine fundamentale Verbesserung gegenüber normalen Custom Properties, die bei fehlendem Wert einen leeren String zurückgeben und damit potentiell ungültige CSS-Deklarationen erzeugen. Mit @property und einem deklarierten initial-value ist das Custom Property immer in einem validen Zustand.
Der initial-value muss mit dem syntax-Typ kompatibel sein – ein <color>-Property kann nicht den Initial-Value 0px haben. Der Browser validiert diese Konsistenz beim Parsen der @property-Deklaration. Im Fehlerfall wird die gesamte @property-Deklaration verworfen und das Property verhält sich wie eine normale, untypisierte Custom Property. Das macht die Deklaration robust gegen Schreibfehler und erleichtert das Debugging in komplexen Design-Systemen erheblich.
5. Animierbarkeit: Custom Properties interpolieren
Der wichtigste praktische Nutzen von CSS @property ist die Animierbarkeit typisierter Custom Properties. Ohne @property behandelt der Browser Custom Properties als Strings und kann zwischen zwei Werten nicht interpolieren – eine Transition auf --mein-wert springt sofort zum Zielwert, anstatt flüssig überzugehen. Mit einer typisierten @property-Deklaration ändert sich das fundamental: Der Browser kennt den Typ und kann numerische Interpolation durchführen.
Das öffnet völlig neue Möglichkeiten in der CSS-Animation. Statt eine Transition auf transform: rotate(45deg) direkt zu definieren, kann man das Rotationsausmaß in einem <angle>-typisierten Custom Property speichern und dieses Property animieren. Das bedeutet, dass eine einzige CSS-Klasse den animierbaren Wert ändern kann, und die Transition wird automatisch ausgelöst. Für Progress-Indikatoren, Füllstandsanzeigen und Farbübergänge ist @property damit die eleganteste CSS-Lösung – ohne JavaScript-Animation-Libraries.
/*
* Animatable gradient using @property
* Without @property: gradients cannot be transitioned
* With @property: each color stop can be interpolated
*/
@property --gradient-start {
syntax: '<color>';
inherits: false;
initial-value: #7c3aed;
}
@property --gradient-end {
syntax: '<color>';
inherits: false;
initial-value: #4a1d96;
}
@property --progress-value {
syntax: '<percentage>';
inherits: false;
initial-value: 0%;
}
/* Hero with animatable gradient */
.hero-gradient {
background: linear-gradient(
135deg,
var(--gradient-start),
var(--gradient-end)
);
transition:
--gradient-start 0.6s ease,
--gradient-end 0.6s ease;
}
.hero-gradient:hover {
--gradient-start: #c4b5fd;
--gradient-end: #7c3aed;
}
/* Progress bar with @property animation */
.progress-bar {
--progress-value: 0%;
width: var(--progress-value);
background: linear-gradient(90deg, #7c3aed, #c4b5fd);
height: 6px;
border-radius: 3px;
transition: --progress-value 0.5s cubic-bezier(0.22, 1, 0.36, 1);
}
/* Keyframe animation on a custom property */
@keyframes spin-dial {
from { --rotation: 0deg; }
to { --rotation: 360deg; }
}
.dial {
transform: rotate(var(--rotation));
animation: spin-dial 2s linear infinite;
}
6. Gradienten mit @property animieren
Das häufigste und beeindruckendste Anwendungsbeispiel für CSS @property ist die Animation von Gradienten. In normalem CSS können Gradienten nicht mit Transitions animiert werden, weil der Browser die Farbstopps als Strings behandelt und nicht interpolieren kann. Mit @property werden die Farbwerte innerhalb des Gradienten als typisierte <color>-Properties definiert. Der Gradient selbst bleibt unveränderlich in seiner Funktion, aber seine Eingabewerte – die Custom Properties – können nun smooth transitioniert werden.
Dieses Muster ist für moderne Web-UIs besonders wertvoll: Hero-Sektionen, die beim Hover ihre Farbe ändern, Buttons mit animierten Farbverläufen, Ladebalken mit dynamischer Farbe und Progress-Indikatoren, die ihren Verlauf basierend auf einem Prozentwert anpassen – all das lässt sich mit @property in reinem CSS implementieren. Früher waren für solche Effekte JavaScript-Bibliotheken wie GSAP erforderlich, die den DOM auf Animationsframe-Basis aktualisieren. @property gibt diese Aufgabe vollständig an den Browser zurück.
7. Zahlen-Properties für CSS-Counter und Layout
Neben Farben und Gradienten sind <number>-typisierte Custom Properties ein weiterer mächtiger Anwendungsfall. Ein häufig genutztes Muster ist der animierte Zähler: Eine @property-Deklaration mit syntax: '<integer>' und einem Startwert von 0. Durch eine @keyframes-Animation, die die Property von 0 auf den Zielwert animiert, und eine counter()-Funktion in content, die den Wert anzeigt, entsteht ein rein CSS-basierter animierter Zahlen-Counter. Kein JavaScript, keine DOM-Manipulation, keine requestAnimationFrame-Schleife.
<number>-Properties eignen sich auch für CSS-Custom-Easing-Kurven, die als Eingabewerte für komplexe calc()-Ausdrücke dienen. Eine Zustandsmaschine in CSS, die zwischen 0 und 1 animiert und verschiedene Eigenschaften proportional steuert, ist mit @property elegant umsetzbar. Zusammen mit @keyframes und animation-timeline entstehen damit Animationssysteme, die vollständig im CSS verbleiben und keine JavaScript-Koordination benötigen.
/* CSS counter animation using @property <integer> */
@property --count {
syntax: '<integer>';
inherits: false;
initial-value: 0;
}
.stat-counter {
counter-reset: count var(--count);
animation: count-up 2s cubic-bezier(0.22, 1, 0.36, 1) both;
animation-delay: 0.3s;
}
.stat-counter::after {
content: counter(count);
font-variant-numeric: tabular-nums;
font-feature-settings: "tnum";
}
/* Animate to the target value via CSS custom property */
@keyframes count-up {
from { --count: 0; }
to { --count: 1247; } /* Target number */
}
/* Staggered counting for multiple stats */
.stats-grid .stat:nth-child(1) { animation-delay: 0.1s; }
.stats-grid .stat:nth-child(2) { animation-delay: 0.2s; }
.stats-grid .stat:nth-child(3) { animation-delay: 0.3s; }
/* Number-driven layout animation */
@property --panel-weight {
syntax: '<number>';
inherits: false;
initial-value: 1;
}
.panel {
flex: var(--panel-weight);
transition: --panel-weight 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.panel:focus-within {
--panel-weight: 2.5;
}
8. CSS.registerProperty() in JavaScript
CSS @property hat ein JavaScript-Äquivalent: CSS.registerProperty(). Diese API erfüllt dieselbe Aufgabe wie die CSS-Regel, ist aber aus JavaScript heraus nutzbar. Das ist besonders relevant für Web-Components und JavaScript-Frameworks, bei denen CSS-Registrierungen programmatisch erfolgen sollen. Die Signatur lautet CSS.registerProperty({ name: '--property-name', syntax: '<color>', inherits: false, initialValue: '#000' }). Die Property-Namen, Syntax-Strings und semantischen Regeln sind identisch mit der CSS-Variante.
Ein wichtiger Unterschied zwischen @property und CSS.registerProperty(): Die CSS-Variante gilt für alle Elemente im Dokument, sobald das Stylesheet geladen ist. CSS.registerProperty() muss vor der ersten Verwendung der Property aufgerufen werden. Wird eine Property registriert, die bereits existiert, wirft die Methode einen InvalidModificationError. In praktischen Web-Component-Implementierungen prüft man daher zunächst, ob die Property bereits registriert wurde, bevor man registerProperty() aufruft. Die Registrierung ist global und kann nicht rückgängig gemacht werden.
9. @property vs. untypisierte Custom Properties
Der direkte Vergleich zeigt, wann CSS @property unbedingt notwendig ist und wann normale Custom Properties ausreichen. Für rein statische Design-Tokens, die als Strings verwendet werden – beispielsweise Font-Familie oder Shadow-Definitionen – ist @property nicht notwendig. Sobald Animationen, Transitions oder Validierung ins Spiel kommen, ist @property die einzige native CSS-Lösung.
| Eigenschaft | Custom Property (--var) | @property | Relevanz |
|---|---|---|---|
| Typ-Validierung | Kein Typ, beliebiger String | Typisiert, ungültig → initial-value | Design-Systeme, Tokens |
| Transitions | Nicht interpolierbar | Vollständig animierbar | Farbübergänge, Fades |
| Vererbung | Immer vererbt | Steuerbar (inherits: false) | Animations-Scope |
| Fallback-Wert | Leerer String oder var(--x, fallback) | initial-value immer valide | Robustheit, Debugging |
| Browser-Support | Alle Browser seit 2017 | Chrome 85+, FF 128+, Safari 16.4+ | Progressive Enhancement |
Die Browser-Unterstützung für @property hat sich 2024 erheblich verbessert. Firefox 128 und Safari 16.4 haben vollständige Unterstützung eingeführt, womit @property heute in über 88% aller Browser-Versionen verfügbar ist. Der empfohlene Ansatz ist Progressive Enhancement: @property deklarieren, aber den Code so schreiben, dass er auch ohne Interpolation korrekt funktioniert – der Effekt verbessert sich für Nutzer mit Unterstützung, und für andere gibt es einen funktionalen, nur nicht animierten Fallback.
Mironsoft
Modernes CSS, Design-Token-Systeme und Hyvä-Frontend-Engineering
Typisierte CSS-Animations-Systeme aufbauen?
Wir implementieren @property-basierte Design-Token-Systeme, animierbare Gradienten und robuste Custom-Property-Architekturen für eure Hyvä- und Tailwind-Projekte.
Token-System
@property-basierte Design-Tokens mit Validierung und initialem Wert einführen
Animationen
Gradienten, Farben und Zahlen mit @property animierbar machen
Hyvä / Tailwind
@property in Tailwind v4.0 und Hyvä-Themes integrieren
10. Zusammenfassung
CSS @property ist das Houdini-Feature, das CSS Custom Properties von untypisierten Strings zu vollwertigen, animierbaren CSS-Werten macht. Die drei Descriptors – syntax, inherits und initial-value – geben dem Browser die Informationen, die er für Interpolation, Validierung und korrekte Vererbung benötigt. Gradienten, Farben, Zahlen und Winkel lassen sich damit mit CSS-Transitions und @keyframes-Animationen verbinden – ohne JavaScript, ohne Bibliotheken.
Die praktischen Anwendungsfälle sind vielfältig: animierte Gradient-Heros, Progress-Indikatoren, rein CSS-basierte Counter-Animationen, robuste Design-Token-Systeme mit Typ-Validierung und komponentenlokale Animation-Properties mit inherits: false. Die Browser-Unterstützung ist seit 2024 vollständig für alle modernen Browser, womit @property heute produktionsreif ist. CSS.registerProperty() bietet dieselbe Funktionalität aus JavaScript für Web-Components und dynamische Registrierung. Kein modernes CSS-Animations-System sollte @property ignorieren.
CSS @property — Das Wichtigste auf einen Blick
syntax-Descriptor
Typen: <color>, <length>, <number>, <percentage>, <angle>. Nur numerische und Farbtypen sind interpolierbar.
initial-value
Pflicht bei nicht-vererbendem Property. Valider Fallback bei ungültigem Wert. Muss mit syntax kompatibel sein.
Animierbarkeit
Gradienten, Farben und Zahlen per transition und @keyframes interpolieren. Kein JavaScript nötig.
registerProperty()
CSS.registerProperty() — JavaScript-Äquivalent für Web-Components. Vor erster Verwendung aufrufen.
11. FAQ: CSS @property
1Was ist CSS @property?
2Warum Custom Properties nicht animierbar?
3Welche syntax-Typen gibt es?
4inherits: false — was bedeutet das?
5Wozu initial-value?
6Gradienten animieren?
7CSS.registerProperty()?
CSS.registerProperty({ name, syntax, inherits, initialValue }). Vor erster Verwendung aufrufen. Nützlich für Web-Components.