CSS · @property · Houdini · Custom Properties
CSS @property
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.

11 Min. Lesezeit @property · syntax · inherits · initial-value · registerProperty Chrome 85+ · Firefox 128+ · Safari 16.4+

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?
Houdini-Regel zum Typisieren von Custom Properties. Mit syntax, inherits und initial-value werden CSS-Variablen animierbar, validiert und in ihrer Vererbung steuerbar.
2Warum Custom Properties nicht animierbar?
Untypisierte Strings — Browser weiß nicht, wie er interpolieren soll. Mit @property und Typ-Descriptor kann der Browser numerisch interpolieren.
3Welche syntax-Typen gibt es?
<color>, <length>, <number>, <percentage>, <angle>, <time>, <transform-list>. Interpolierbar: Farb- und Zahlentypen.
4inherits: false — was bedeutet das?
Property wird nicht im DOM-Baum vererbt. Gilt nur für direkt gesetztes Element. Nützlich für animations-lokale Properties ohne Seiteneffekte.
5Wozu initial-value?
Valider Fallback bei fehlendem oder ungültigem Wert. Muss mit syntax-Typ kompatibel sein. Pflicht bei inherits: false.
6Gradienten animieren?
Farbstopps als @property <color> definieren. Gradient mit var() aufbauen. transition auf Properties — Browser interpoliert die Farben smooth.
7CSS.registerProperty()?
JavaScript-Äquivalent. CSS.registerProperty({ name, syntax, inherits, initialValue }). Vor erster Verwendung aufrufen. Nützlich für Web-Components.
8Browser-Unterstützung?
Chrome 85+, Firefox 128+, Safari 16.4+. Über 88% global. Progressive Enhancement: Code ohne Animation als Fallback schreiben.
9Wann @property statt Custom Property?
Bei Transitions oder Keyframes auf Custom Properties. Bei Typ-Validierung für Design-Tokens. Bei Vererbungskontrolle. Reine String-Tokens: normale Custom Properties reichen.
10@property mit Tailwind v4.0?
Direkt in der CSS-Konfigurationsdatei deklarieren. Properties stehen projektübergreifend zur Verfügung und können in Tailwind-Utilities verwendet werden.