CSS Paint API: Ein eigenes Paint Worklet für Hintergrundmuster bauen
AI generated
{ }
@
CSS · Houdini · Paint API · Performance
Die CSS Paint API in der Praxis
Ein eigenes Paint Worklet für ein wiederverwendbares Hintergrundmuster

Ein Paint Worklet zeichnet einen Hintergrund nicht als fertige Bilddatei, sondern als kleines JavaScript-Programm, das der Browser bei jedem Repaint direkt in den Element-Hintergrund rendert. Wer einmal ein parametrisierbares Muster als Worklet registriert, kann es über CSS Custom Properties in beliebig vielen Komponenten wiederverwenden, ohne für jede Farbvariante eine neue SVG-Datei zu exportieren.

15 Min. Lesezeit registerPaint · paint() · @property Chrome · Edge · Firefox (Flag) · Safari (kein Support)

1. Was die CSS Paint API ist und wie sie sich in die Cascade einklinkt

Die CSS Paint API ist Teil der Houdini-Initiative und erlaubt es, eine JavaScript-Funktion als gültigen Wert für background-image und ähnliche Bild-Eigenschaften zu registrieren. Statt einer URL oder eines Gradienten steht dort paint(mustername), und der Browser ruft bei jedem Layout- oder Style-Wechsel die registrierte paint()-Methode des Worklets auf, die auf einer Canvas-ähnlichen Zeichenfläche direkt in den Element-Hintergrund malt.

Der entscheidende Unterschied zu einem klassischen background: url(...) ist, dass ein Paint Worklet keine fertige Datei lädt, sondern bei jedem Aufruf neu rechnet, basierend auf der aktuellen Elementgröße und den übergebenen Custom Properties. Das macht Worklets besonders für Muster interessant, die sich responsiv an die Boxgröße anpassen sollen, etwa ein Punktraster, das bei jeder Breakpoint-Änderung neu und scharf gezeichnet wird, statt wie ein skaliertes Bild zu verschwimmen.

2. Ein erstes Worklet registrieren: registerPaint und addModule

Ein Paint Worklet lebt in einer eigenen JavaScript-Datei, die in einem separaten Thread ausgeführt wird und keinen Zugriff auf das DOM hat. Innerhalb dieser Datei ruft man registerPaint(name, klasse) auf und übergibt eine Klasse mit einer paint(ctx, size, properties)-Methode, die auf dem übergebenen 2D-Kontext zeichnet. Der Hauptdokument-Code lädt dieses Modul asynchron über CSS.paintWorklet.addModule(pfad), bevor der erste Paint-Aufruf im Stylesheet greifen kann.

Wichtig ist, dass addModule ein Promise zurückgibt und der Browser das Muster erst zeichnet, sobald das Modul geladen ist. Bei einem sehr frühen ersten Render kann deshalb kurzzeitig kein Hintergrund sichtbar sein. In der Praxis registriert man das Worklet deshalb so früh wie möglich im Kopf des Dokuments und plant einen unauffälligen Fallback-Hintergrund über CSS ein, der greift, solange das Worklet noch nicht bereitsteht.


// dot-pattern-worklet.js -- registered as a CSS Paint Worklet
class DotPatternPainter {
  static get inputProperties() {
    return ['--dot-color', '--dot-size', '--dot-gap'];
  }

  paint(ctx, size, properties) {
    const color = properties.get('--dot-color').toString().trim() || '#7c3aed';
    const dotSize = parseFloat(properties.get('--dot-size')) || 2;
    const gap = parseFloat(properties.get('--dot-gap')) || 18;

    ctx.fillStyle = color;
    for (let y = gap / 2; y < size.height; y += gap) {
      for (let x = gap / 2; x < size.width; x += gap) {
        ctx.beginPath();
        ctx.arc(x, y, dotSize, 0, Math.PI * 2);
        ctx.fill();
      }
    }
  }
}

registerPaint('dot-pattern', DotPatternPainter);

3. Das Worklet in CSS einbinden: paint() als Hintergrundwert

Sobald das Modul geladen ist, verhält sich paint(dot-pattern) in CSS wie jeder andere background-image-Wert: Es lässt sich mit background-size, mehreren Layern über Kommas und sogar mit background-blend-mode kombinieren. Für die Karte einer Produktseite reicht damit ein einziger CSS-Block, um ein Punktraster als dekorativen Hintergrund zu setzen, ganz ohne zusätzliche HTTP-Anfrage für eine Bilddatei.

Das Laden des Moduls geschieht im Hauptdokument mit wenigen Zeilen JavaScript und muss nur einmal pro Seite passieren, unabhängig davon, wie viele Elemente das Muster später verwenden. Dieses einmalige Setup ist einer der praktischen Vorteile gegenüber mehreren einzelnen SVG-Dateien, die jede für sich geladen und vom Browser gecacht werden müssten.


.product-card {
  --dot-color: #7c3aed;
  --dot-size: 1.5px;
  --dot-gap: 16px;
  background-image: paint(dot-pattern);
  background-color: #faf5ff;
}

.product-card--dark {
  --dot-color: #c4b5fd;
  background-color: #1e1033;
}

4. Werte an das Worklet übergeben: inputProperties und @property

Ein Worklet erhält Werte aus CSS ausschließlich über die in inputProperties aufgelisteten Custom Properties, alle anderen CSS-Eigenschaften des Elements sind für das Worklet unsichtbar. Deshalb müssen Farbe, Punktgröße und Abstand des Musters explizit als eigene Custom Properties definiert und in der statischen Getter-Liste der Painter-Klasse angemeldet werden, sonst liefert properties.get(...) im Worklet einen leeren Wert zurück.

Registriert man diese Custom Properties zusätzlich mit @property, bekommt das Worklet garantiert typisierte, geparste Werte statt roher Strings, und der Browser kann zwischen zwei Werten sogar animieren, etwa den Punktabstand beim Hover sanft zu vergrößern. Ohne Registrierung bleibt jede Custom Property ein reiner Text-Token, den das Worklet selbst parsen muss, was Tippfehler bei Einheiten erst zur Laufzeit sichtbar macht.


@property --dot-gap {
  syntax: '<length>';
  inherits: false;
  initial-value: 16px;
}

.product-card:hover {
  --dot-gap: 24px; /* animatable because --dot-gap is typed as <length> */
  transition: --dot-gap 0.4s ease;
}

5. Wiederverwendbarkeit: ein Muster für mehrere Komponenten parametrisieren

Der eigentliche Gewinn eines Paint Worklets zeigt sich erst, wenn ein einziges registriertes Muster in einem ganzen Design-System für Karten, Hero-Sektionen und Badges gleichzeitig genutzt wird, jeweils mit anderen Custom-Property-Werten für Farbe und Dichte. Statt fünf separater SVG-Dateien für fünf Farbvarianten pflegt man eine JavaScript-Datei und variiert das Ergebnis komplett über CSS, was die Wartung deutlich vereinfacht, sobald sich die Markenfarbe ändert.

Diese Parametrisierung funktioniert auch über Media Queries und Container Queries hinweg, weil das Worklet bei jeder relevanten Style-Änderung erneut aufgerufen wird. Ein Punktraster kann so auf kleinen Viewports automatisch enger werden, indem --dot-gap innerhalb einer Media Query einfach überschrieben wird, ohne dass eine zweite, für mobile Geräte optimierte Bilddatei ausgeliefert werden muss.

6. Performance-Vergleich: Paint Worklet gegen SVG-Background und Bilddatei

Ein statisches SVG oder PNG als Hintergrund wird einmal vom Browser dekodiert und danach aus dem Bild-Cache gezeichnet, was pro Frame extrem günstig ist, aber jede Größenänderung als Skalierung eines bereits fertigen Bitmaps behandelt. Ein Paint Worklet zeichnet dagegen bei jedem Repaint neu, was für ein einfaches Punktraster auf modernen Geräten kaum messbar ist, bei komplexen, rechenintensiven Mustern mit vielen Pfaden aber echte Repaint-Kosten verursacht, die ein Profiling im Performance-Panel sichtbar macht.

Der Vorteil liegt nicht in der reinen Zeichengeschwindigkeit, sondern darin, dass ein Worklet keine zusätzliche Datei über das Netzwerk lädt und beliebig viele Farbvarianten ohne neuen Request erzeugt, während für dieselbe Flexibilität mit SVG entweder mehrere Dateien oder eine per JavaScript generierte Data-URI nötig wären. Für seltene Repaints, etwa einen statischen Kartenhintergrund, ist ein optimiertes SVG oft weiterhin die günstigere Wahl, für stark parametrisierte, häufig wechselnde Muster gewinnt in der Praxis meist das Worklet.

7. Wann sich ein Paint Worklet nicht lohnt

Für einfache geometrische Muster, die sich mit CSS-Gradienten allein abbilden lassen, etwa Streifen, Schachbrettmuster oder weiche Farbverläufe, ist ein Paint Worklet reiner Overhead: Ein repeating-linear-gradient erreicht dasselbe visuelle Ergebnis ohne zusätzliche JavaScript-Datei, ohne Ladezeit für addModule und mit vollem Support auch in Safari, wo Paint Worklets bis heute fehlen.

Auch wenn ein Muster nur einmal auf der gesamten Seite vorkommt und sich nie ändert, überwiegt der Aufwand für Registrierung und Modul-Ladezeit den Nutzen gegenüber einer einzelnen, sauber optimierten SVG-Datei. Ein Paint Worklet lohnt sich am meisten dort, wo echte Parametrisierbarkeit über viele Komponenten hinweg gebraucht wird, nicht als Ersatz für jedes dekorative Hintergrundbild.

8. Browser-Support und eine robuste Fallback-Strategie

Chrome und Edge unterstützen die CSS Paint API seit mehreren Jahren vollständig, Firefox bietet sie nur hinter einem experimentellen Flag an, und Safari implementiert bislang keinen der Houdini-Paint-Bausteine. Damit ist die API für produktive Projekte klar ein Progressive-Enhancement-Feature: Sie darf niemals die einzige Quelle für einen inhaltlich wichtigen Hintergrund sein, sondern immer eine Verbesserung on top of einem funktionierenden CSS-Fallback.

Die Feature-Detection erfolgt am saubersten über @supports (background-image: paint(x)), weil das die tatsächliche Fähigkeit des Browsers prüft, statt sich auf eine JavaScript-Prüfung von CSS.paintWorklet zu verlassen, die in älteren Browsern selbst schon einen Fehler werfen kann. Innerhalb des @supports-Blocks lädt man dann optional zusätzlich das Worklet-Modul per JavaScript, außerhalb bleibt ein einfacher Gradient oder ein statisches Bild als solide Basis bestehen.


.product-card {
  /* Fallback for every browser without CSS Paint API support */
  background-image: radial-gradient(circle, #c4b5fd 1.5px, transparent 1.5px);
  background-size: 16px 16px;
}

@supports (background-image: paint(dot-pattern)) {
  .product-card {
    background-image: paint(dot-pattern);
  }
}

9. Debugging und Entwicklungsworkflow für Paint Worklets

Fehler innerhalb eines Worklets landen nicht automatisch in der normalen Konsole des Hauptdokuments, weil der Code in einem eigenen, isolierten Worklet-Kontext läuft. In Chrome DevTools lässt sich dieser Kontext über das Dropdown-Menü oben in der Konsole gezielt auswählen ("Paint Worklet"), um Log-Ausgaben und Exceptions aus paint() direkt zu sehen, statt im Dunkeln zu debuggen, warum ein Hintergrund einfach leer bleibt.

Ein typischer Debugging-Fehler ist, eine Custom Property zu ändern, ohne sie in inputProperties aufgelistet zu haben: Das Worklet erhält dann stillschweigend keinen aktualisierten Wert, und es entsteht der Eindruck, CSS-Änderungen würden ignoriert. Wer neue Parameter einführt, sollte deshalb immer zuerst die statische Getter-Liste erweitern und erst danach die zugehörige CSS Custom Property im Stylesheet nutzen.

Ansatz Netzwerk-Request Responsive Schärfe Parametrisierbarkeit
paint() Worklet Ein Modul, einmalig pro Seite Immer scharf, neu berechnet Beliebig viele Varianten per Custom Property
SVG als Background Eine Datei pro Variante Skalierbar, aber statisch Nur über mehrere Dateien oder Data-URI
PNG/JPEG als Background Eine Datei pro Variante Verliert Schärfe bei Skalierung Keine, feste Pixelwerte
CSS-Gradient Kein Request Immer scharf Über Custom Properties möglich, aber geometrisch begrenzt

Mironsoft

Modernes CSS, Layout-Architektur und Rendering-Performance

CSS, das wartbar bleibt statt mit jeder Änderung zu brechen?

Wir prüfen bestehende Stylesheets auf Spezifitäts-Chaos und Layout-Thrashing und bauen daraus eine CSS-Architektur mit Cascade Layers, Custom Properties und modernen Layout-Primitiven, die auch nach dem zehnten Feature noch verständlich ist.

CSS-Audit

Spezifität, Cascade-Konflikte und ungenutzte Selektoren systematisch aufdecken.

Architektur-Refactoring

Cascade Layers, Custom Properties und Design Tokens sauber einführen.

Performance-Tuning

Layout-Thrashing, teure Selektoren und Rendering-Engpässe gezielt beheben.

10. Zusammenfassung

CSS Paint Worklets: Das Wichtigste auf einen Blick

Grundprinzip

Ein Paint Worklet registriert eine JavaScript-Klasse mit paint()-Methode, die bei jedem Repaint direkt in den Hintergrund zeichnet.

Werte übergeben

inputProperties listet die Custom Properties, die das Worklet lesen darf. @property macht sie typisiert und animierbar.

Performance

Kein zusätzlicher Netzwerk-Request pro Variante, aber echte Rechenkosten bei jedem Repaint für komplexe Muster.

Fallback-Pflicht

@supports (background-image: paint(x)) prüfen und immer einen CSS-Fallback für Safari und ältere Firefox-Versionen bereithalten.

11. FAQ: CSS Paint Worklets: Das Wichtigste auf einen Blick

1Was ist die CSS Paint API überhaupt?
Ein Teil der Houdini-Initiative, mit dem eine JavaScript-Funktion als Wert für background-image registriert werden kann. Der Browser ruft diese Funktion bei jedem Repaint auf und zeichnet direkt in den Hintergrund.
2Wie registriere ich ein Paint Worklet?
In einer eigenen JavaScript-Datei mit registerPaint(name, klasse) eine Klasse mit paint(ctx, size, properties) definieren und diese Datei im Hauptdokument mit CSS.paintWorklet.addModule(pfad) laden.
3Wie kommen CSS-Werte in das Worklet?
Nur über Custom Properties, die in der statischen inputProperties-Liste der Painter-Klasse aufgeführt sind. Alle anderen CSS-Eigenschaften des Elements sind für das Worklet unsichtbar.
4Was bringt @property in Kombination mit einem Worklet?
@property gibt der Custom Property einen festen Typ und einen Initialwert, sodass das Worklet garantiert geparste Werte erhält und der Browser zwischen zwei Werten animieren kann.
5Ist ein Paint Worklet schneller als ein SVG-Hintergrund?
Nicht grundsätzlich. Ein SVG wird einmal dekodiert und danach günstig aus dem Cache gezeichnet, ein Worklet rechnet bei jedem Repaint neu. Der Vorteil liegt in der Parametrisierbarkeit ohne zusätzliche Requests, nicht in der reinen Zeichengeschwindigkeit.
6Welche Browser unterstützen die CSS Paint API?
Chrome und Edge vollständig, Firefox nur hinter einem experimentellen Flag, Safari bislang gar nicht. Die API ist deshalb ein Progressive-Enhancement-Feature.
7Wie baue ich einen sauberen Fallback?
Mit @supports (background-image: paint(name)) prüfen, ob der Browser die API unterstützt, und außerhalb des Blocks einen Gradienten oder ein statisches Bild als Basis definieren.
8Warum bleibt mein Hintergrund manchmal kurz leer?
Weil CSS.paintWorklet.addModule ein Promise zurückgibt und das Muster erst nach dem Laden des Moduls gezeichnet wird. Ein CSS-Fallback-Hintergrund überbrückt diese kurze Lücke.
9Kann ich ein Worklet in DevTools debuggen?
Ja, in Chrome DevTools lässt sich der Worklet-Kontext im Konsolen-Dropdown auswählen, um Log-Ausgaben und Fehler direkt aus der paint()-Methode zu sehen.
10Wann sollte ich lieber bei SVG oder Gradienten bleiben?
Wenn das Muster einfach ist, sich nur einmal ändert oder mit repeating-linear-gradient abbildbar ist. Ein Worklet lohnt sich erst bei echter Parametrisierbarkeit über viele Komponenten hinweg.