CSS Houdini: Erstellen Sie benutzerdefinierte Effekte, die in regulärem CSS nicht verfügbar sind
CSS Houdini: Erstellen Sie benutzerdefinierte Effekte, die in regulärem CSS nicht verfügbar sind
Versuchen Sie etwas scheinbar Einfaches: den Winkel in einem conic-gradient() beim Hover flüssig zu animieren. Sie definieren eine Custom Property --kat: 0deg, fügen transition: --kat 0.4s hinzu, fahren mit der Maus darüber – und nichts passiert. Der Verlauf ändert sich sprunghaft, als würde transition gar nicht existieren. Das ist kein Fehler in Ihrem Code. Für den Browser ist --kat lediglich ein gewöhnlicher, undurchsichtiger String – er weiß nicht, dass es sich um einen Winkel handelt, und kann daher nicht zwischen 0deg und 180deg interpolieren. Zahlen, Farben, Längen kann der Browser interpolieren, weil er ihre Typen kennt. Custom Properties haben, im Gegensatz zu eingebauten CSS-Eigenschaften, überhaupt keinen Typ. Genau in diese Lücke stößt CSS Houdini.
Was Houdini wirklich ist
Das ist ein verbreitetes Missverständnis: Houdini ist weder eine einzelne Technologie noch auch nur eine einzelne Spezifikation. Es ist ein Dachbegriff für mehrere unabhängige Vorschläge beim W3C, die eine gemeinsame Idee verbindet – Teile der Rendering-Engine (Wertparsing, Layout, Malen, Animation) offenzulegen, die zuvor völlig vor Entwicklern verborgen waren. Statt darauf zu warten, dass in CSS eine fertige Eigenschaft erscheint, die genau das tut, was Sie brauchen, erhalten Sie einen niedrigschwelligen Haken in eine konkrete Phase dieses Prozesses.
Diese Haken werden als Worklets umgesetzt – kleine JavaScript-Module, konzeptionell nahe an Web Workern, aber speziell für die Rendering-Pipeline entworfen. Ein Worklet läuft außerhalb des Hauptthreads, hat keinen Zugriff auf window, document oder das DOM und kommuniziert ausschließlich über einen streng definierten Vertrag (z. B. paint(ctx, size, properties)). Das ist keine Einschränkung aus Bequemlichkeit der Spezifikationsautoren – es ist eine bewusste architektonische Entscheidung. Dank der Isolation kann die Engine Worklets parallel, auf separaten Threads, ausführen und das Ergebnis cachen, ohne das Risiko, dass Ihr Code etwas berührt, was er nicht sollte. Dieselbe Isolation ist der Grund, warum Sie innerhalb eines Worklets weder Date, performance.now() noch fetch finden – die eingeschränkte Verfügbarkeit präziser Zeit- und Netzwerkzugriffe ist ein bewusster Schutz vor Timing-/Fingerprinting-Angriffen aus dem Code, der die Seite rendert.
Die einzelnen Teile dieses Dachbegriffs befinden sich heute auf ganz unterschiedlichen Stufen: Der eine ist seit Langem Teil von Baseline, ein anderer funktioniert nur in Chrome, und wieder ein anderer ist nach einem Jahrzehnt immer noch ein Experiment. Diese Unterscheidung ist entscheidend – und die meisten einführenden Artikel über Houdini übergehen sie, indem sie das Ganze als eine einzige, gebrauchsfertige Technologie behandeln.
Das einzige Houdini, das man heute wirklich nutzen sollte: @property
Die CSS Properties and Values API löst genau das Problem, mit dem dieser Artikel begann. Sie registrieren eine Custom Property mit einem konkreten Typ (syntax), einem Anfangswert und der Information, ob sie vererbt werden soll – und ab diesem Moment behandelt der Browser sie wie einen vollwertigen, animierbaren Wert, nicht wie einen String.
html
<div class="ring"></div>
css
@property --kat {syntax: '<angle>';inherits: false;initial-value: 0deg;}.ring {width: 200px;height: 200px;border-radius: 50%;background: conic-gradient(from var(--kat), #ff4d4d, #4d79ff, #4dff88, #ff4d4d);transition: --kat 0.6s ease;}.ring:hover {--kat: 180deg;}
Dieses Beispiel tut tatsächlich etwas, das gewöhnliches CSS nicht kann – ohne @property würde die obige transition schlicht nicht funktionieren, genau wie im Szenario zu Beginn des Artikels. syntax: '<angle>' teilt dem Browser mit, dass --kat ein Winkel ist, sodass er flüssig interpolieren kann; inherits: false verhindert, dass Kind-Elemente den Wert versehentlich erben, was bei Custom Properties oft eine Quelle schwer auffindbarer Fehler ist.
Denselben Effekt kann man auch aus JavaScript heraus erzielen, was sinnvoll ist, wenn Sie Eigenschaften dynamisch registrieren (z. B. datenbasiert generiert) statt sie fest im Stylesheet zu verankern:
javascript
if ('registerProperty' in CSS) {CSS.registerProperty({name: '--kat',syntax: '<angle>',inherits: false,initialValue: '0deg',});}
Dies ist der einzige Teil von Houdini, der heute den Status Baseline hat – er funktioniert nativ in Chrome, Firefox (ab Version 128) und Safari (ab 16.4), ohne Polyfills und ohne @supports. Wenn Sie sich aus dem gesamten Houdini nur eine Sache merken und umsetzen sollten, dann genau diese.
CSS Paint API: ein Worklet, das wirklich malt
Die Paint API erlaubt es, background durch die Funktion paint() zu ersetzen, die direkt auf dem Element zeichnet und dabei eine abgespeckte, an Canvas 2D erinnernde Schnittstelle (PaintRenderingContext2D) nutzt – ohne fillText, drawImage oder das Auslesen von Pixeln. Was diesen Ansatz vom gewöhnlichen Zeichnen auf einem <canvas> unterscheidet, sind die inputProperties: Das Worklet deklariert, welche Custom Properties es beobachten möchte, und zeichnet sich automatisch nur dann neu, wenn sich eine davon ändert – ohne eine einzige Zeile JavaScript, die für das Abhören von Ereignissen zuständig wäre.
Unten ein Muster aus warnenden, diagonalen Streifen, deren Winkel über dieselbe, zuvor registrierte Eigenschaft --kat gesteuert wird (genauer über ihre lokale Variante --stripe-angle) – was zeigt, wie sich @property und die Paint API auf natürliche Weise ergänzen.
html
<div class="hazard"></div>
css
@property --stripe-angle {syntax: '<angle>';inherits: false;initial-value: 45deg;}.hazard {width: 100%;height: 120px;--stripe-angle: 45deg;background: paint(hazardStripes);transition: --stripe-angle 0.4s ease;}.hazard:hover {--stripe-angle: 135deg;}
javascript
// main.jsif ('paintWorklet' in CSS) {CSS.paintWorklet.addModule('hazard-stripes.js');}
javascript
// hazard-stripes.jsclass HazardStripesPainter {static get inputProperties() {return ['--stripe-angle'];}paint(ctx, size, properties) {const angle = properties.get('--stripe-angle').to('deg').value;const stripeWidth = 24;const { width, height } = size;const diagonal = Math.sqrt(width ** 2 + height ** 2) * 2;ctx.save();ctx.translate(width / 2, height / 2);ctx.rotate((angle * Math.PI) / 180);ctx.translate(-diagonal, -diagonal);let stripeIndex = 0;for (let x = 0; x < diagonal * 2; x += stripeWidth) {ctx.fillStyle = stripeIndex % 2 === 0 ? '#111111' : '#f5c400';ctx.fillRect(x, 0, stripeWidth, diagonal * 2);stripeIndex++;}ctx.restore();}}registerPaint('hazardStripes', HazardStripesPainter);
Beachtenswert ist properties.get('--stripe-angle').to('deg').value – das ist CSS Typed OM, ein weiteres Mitglied derselben Familie von APIs. Statt den String manuell zu parsen (parseFloat, Abschneiden von "deg"), erhalten Sie einen typisierten Wert CSSUnitValue, den Sie explizit in die benötigte Einheit umwandeln. Da der Winkel der gezeichneten Streifen ausschließlich von der in inputProperties deklarierten Custom Property abhängt, weiß die Engine genau, wann ein Neuzeichnen nötig ist – die Änderung einer nicht verwandten CSS-Eigenschaft anderswo auf der Seite löst paint() nicht erneut aus.
Layout API und Animation Worklet: die Realität 2026
Hier beginnt der Teil, über den die meisten einführenden Artikel zu Houdini schweigen. Die CSS Layout API – die dritte Säule derselben Spezifikation, mit der man einen eigenen Layout-Algorithmus definieren kann (das Äquivalent eines eigenen display: grid) – existiert seit 2015 als Entwurf und ist nach einem Jahrzehnt immer noch experimentell. Kein stabiler Browser hat sie nativ implementiert; verfügbar ist sie ausschließlich hinter Flags oder in Chrome-Origin-Trials. Wenn Sie auf einen Artikel stoßen, der display: layout(name) als gebrauchsfertige Lösung zeigt, prüfen Sie das Veröffentlichungsdatum – wahrscheinlich handelt es sich um eine Demo aus einem Origin Trial von vor Jahren, nicht um etwas, das Sie heute im Browser eines Nutzers ausführen können.
Der Animation Worklet sollte volle Kontrolle über scrollgesteuerte Animationen geben, ausgeführt außerhalb des Hauptthreads. Real unterstützt wird er nur von Chromium. Wichtiger noch – sein Haupt-Anwendungsfall ist kein Grund mehr, zu Houdini zu greifen, denn CSS hat für dasselbe Problem eine native Lösung erhalten: animation-timeline: scroll() erlaubt es heute, eine Animation ohne eine einzige Zeile JavaScript und ohne Worklets an den Scroll zu koppeln, mit wachsender Browserunterstützung. Das ist eine gute Illustration eines breiteren Musters: Ein Teil der Gründe, aus denen Houdini überhaupt entstand, ist mit der Zeit direkt in die CSS-Spezifikation gewandert, statt eine niedrigschwellige API für Entwickler zu bleiben.
Wann das in der Praxis Sinn ergibt
@propertykönnen Sie bedenkenlos, ohne Absicherungen einsetzen – es hat den Status Baseline und benötigt weder@supportsnoch einen Polyfill.- Die Paint API sollten Sie als progressive Verbesserung behandeln – wickeln Sie sie in
@supports(background: paint(x))mit einem sinnvollen Fallback in reinem CSS (z. B. einem gewöhnlichen Verlauf) für Firefox, oder greifen Sie auf den Polyfillcss-paint-polyfillzurück, wenn der Effekt überall funktionieren muss. - Planen Sie keine produktive Funktion auf Basis der Layout API – sie ist weiterhin ein Experiment ohne echte Browserunterstützung, gut zum Ausprobieren, nicht für die Roadmap.
- Denken Sie daran, dass
paint()kein „kostenloses“ CSS ist – es ist Ihr JavaScript-Code, der bei jeder Änderung der deklarierteninputPropertieserneut ausgeführt wird. Aufwendige Berechnungen (Rauschen generieren, komplexe prozedurale Muster) müssen genauso optimiert werden wie eine Rendering-Schleife auf einem<canvas>– hier baut man leicht versehentlich eine Animation, die das gesamte Element Frame für Frame auf dem Haupt-Layout-Thread neu zeichnet.
Zusammenfassung
Houdini ist keine einzelne Entscheidung „nutzen oder nicht“ – es sind drei, vier separate Entscheidungen mit unterschiedlichem Risiko. Erstens löst @property ein reales, konkretes Problem (das Animieren von Custom Properties) und ist heute genauso sicher in der Anwendung wie jede andere CSS-Eigenschaft – der einzige Teil dieses Ökosystems, den man ohne Zögern einsetzen sollte. Zweitens verleiht die Paint API echte Macht (ein Worklet, das sich nur bei Änderung der deklarierten Abhängigkeiten neu zeichnet, ohne manuelles Abhören von Ereignissen), erfordert aber einen bewussten Plan für Browser ohne Unterstützung – ein Werkzeug für progressive Verbesserung, nicht für kritische Funktionen. Drittens sind die Layout API und der Animation Worklet ein gutes Beispiel dafür, dass eine Spezifikation an sich keine Adoption garantiert – nach Jahren wartet die eine immer noch auf ihre Implementierung, während die andere teilweise durch einfacheres, natives CSS ersetzt wurde. Bevor Sie zu Houdini greifen, prüfen Sie, in welchen dieser drei Körbe genau der Teil fällt, den Sie brauchen.