Neue Möglichkeiten in Chrome 65
Die CSS Paint API (auch als „CSS Custom Paint“ oder „Houdini’s Paint Worklet“ bezeichnet) ist ab Chrome 65 standardmäßig aktiviert. Was ist das? Was kann man damit machen? Und wie funktioniert das? Lesen Sie einfach weiter…
Mit der CSS Paint API können Sie programmatisch ein Bild generieren, wenn für eine CSS-Eigenschaft ein Bild erwartet wird. Eigenschaften wie background-image
oder border-image
werden in der Regel mit url()
verwendet, um eine Bilddatei zu laden, oder mit integrierten CSS-Funktionen wie linear-gradient()
. Stattdessen können Sie jetzt paint(myPainter)
verwenden, um auf ein Paint-Worklet zu verweisen.
Paint-Worklet schreiben
Um ein Paint-Worklet namens myPainter
zu definieren, müssen wir eine CSS-Paint-Worklet-Datei mit CSS.paintWorklet.addModule('my-paint-worklet.js')
laden. In dieser Datei können wir die Funktion registerPaint
verwenden, um eine Paint-Worklet-Klasse zu registrieren:
class MyPainter {
paint(ctx, geometry, properties) {
// ...
}
}
registerPaint('myPainter', MyPainter);
Innerhalb des paint()
-Callbacks können wir ctx
auf dieselbe Weise verwenden wie ein CanvasRenderingContext2D
, das wir aus <canvas>
kennen. Wenn Sie wissen, wie man in einem <canvas>
zeichnet, können Sie auch in einem Paint-Worklet zeichnen. geometry
gibt uns die Breite und Höhe des verfügbaren Canvas an. properties
Das werde ich später in diesem Artikel erläutern.
Als einführendes Beispiel schreiben wir ein Worklet für ein Schachbrettmuster und verwenden es als Hintergrundbild eines <textarea>
. (Ich verwende ein Textfeld, da es standardmäßig in der Größe angepasst werden kann.):
<!-- index.html -->
<!doctype html>
<style>
textarea {
background-image: paint(checkerboard);
}
</style>
<textarea></textarea>
<script>
CSS.paintWorklet.addModule('checkerboard.js');
</script>
// checkerboard.js
class CheckerboardPainter {
paint(ctx, geom, properties) {
// Use `ctx` as if it was a normal canvas
const colors = ['red', 'green', 'blue'];
const size = 32;
for(let y = 0; y < geom.height/size; y++) {
for(let x = 0; x < geom.width/size; x++) {
const color = colors[(x + y) % colors.length];
ctx.beginPath();
ctx.fillStyle = color;
ctx.rect(x * size, y * size, size, size);
ctx.fill();
}
}
}
}
// Register our class under a specific name
registerPaint('checkerboard', CheckerboardPainter);
Wenn Sie <canvas>
schon einmal verwendet haben, sollte Ihnen dieser Code bekannt vorkommen. Live-Demo

Der Unterschied zu einem gemeinsamen Hintergrundbild besteht darin, dass das Muster bei Bedarf neu gezeichnet wird, wenn der Nutzer die Größe des Textbereichs ändert. Das Hintergrundbild ist also immer genau so groß, wie es sein muss, einschließlich der Kompensation für Displays mit hoher Dichte.
Das ist zwar ganz nett, aber auch ziemlich statisch. Müssen wir jedes Mal ein neues Worklet schreiben, wenn wir dasselbe Muster, aber mit unterschiedlich großen Quadraten verwenden möchten? Die Antwort lautet „Nein“.
Worklet parametrisieren
Glücklicherweise kann das Paint-Worklet auf andere CSS-Eigenschaften zugreifen. Hier kommt der zusätzliche Parameter properties
ins Spiel. Wenn Sie der Klasse ein statisches inputProperties
-Attribut zuweisen, können Sie Änderungen an einer beliebigen CSS-Eigenschaft abonnieren, einschließlich benutzerdefinierter Eigenschaften. Die Werte werden Ihnen über den Parameter properties
zur Verfügung gestellt.
<!-- index.html -->
<!doctype html>
<style>
textarea {
/* The paint worklet subscribes to changes of these custom properties. */
--checkerboard-spacing: 10;
--checkerboard-size: 32;
background-image: paint(checkerboard);
}
</style>
<textarea></textarea>
<script>
CSS.paintWorklet.addModule('checkerboard.js');
</script>
// checkerboard.js
class CheckerboardPainter {
// inputProperties returns a list of CSS properties that this paint function gets access to
static get inputProperties() { return ['--checkerboard-spacing', '--checkerboard-size']; }
paint(ctx, geom, properties) {
// Paint worklet uses CSS Typed OM to model the input values.
// As of now, they are mostly wrappers around strings,
// but will be augmented to hold more accessible data over time.
const size = parseInt(properties.get('--checkerboard-size').toString());
const spacing = parseInt(properties.get('--checkerboard-spacing').toString());
const colors = ['red', 'green', 'blue'];
for(let y = 0; y < geom.height/size; y++) {
for(let x = 0; x < geom.width/size; x++) {
ctx.fillStyle = colors[(x + y) % colors.length];
ctx.beginPath();
ctx.rect(x*(size + spacing), y*(size + spacing), size, size);
ctx.fill();
}
}
}
}
registerPaint('checkerboard', CheckerboardPainter);
Jetzt können wir denselben Code für alle Arten von Schachbrettmustern verwenden. Noch besser ist, dass wir jetzt in die DevTools gehen und mit den Werten herumspielen können, bis wir den richtigen Look gefunden haben.
Browser, die Paint Worklet nicht unterstützen
Zum Zeitpunkt der Erstellung dieses Dokuments ist das Paint Worklet nur in Chrome implementiert. Es gibt zwar positive Signale von allen anderen Browseranbietern, aber es gibt nicht viele Fortschritte. Auf der Seite Is Houdini Ready Yet? finden Sie aktuelle Informationen. Verwenden Sie in der Zwischenzeit Progressive Enhancement, damit Ihr Code auch dann ausgeführt wird, wenn keine Unterstützung für Paint Worklet vorhanden ist. Damit alles wie erwartet funktioniert, müssen Sie Ihren Code an zwei Stellen anpassen: im CSS und im JS.
Die Unterstützung für Paint Worklet in JS kann durch Überprüfen des CSS
-Objekts erkannt werden:
js
if ('paintWorklet' in CSS) {
CSS.paintWorklet.addModule('mystuff.js');
}
Auf der CSS-Seite haben Sie zwei Möglichkeiten. Sie können @supports
verwenden, um:
@supports (background: paint(id)) {
/* ... */
}
Ein kompakterer Trick besteht darin, dass CSS eine gesamte Eigenschaftendeklaration ungültig macht und ignoriert, wenn darin eine unbekannte Funktion enthalten ist. Wenn Sie eine Eigenschaft zweimal angeben – zuerst ohne Paint-Worklet und dann mit dem Paint-Worklet –, erhalten Sie Progressive Enhancement:
textarea {
background-image: linear-gradient(0, red, blue);
background-image: paint(myGradient, red, blue);
}
In Browsern mit Unterstützung für Paint Worklet wird die zweite Deklaration von background-image
die erste überschreiben. In Browsern ohne Unterstützung für Paint Worklet ist die zweite Deklaration ungültig und wird verworfen. Die erste Deklaration bleibt in Kraft.
CSS Paint-Polyfill
Für viele Anwendungsfälle ist es auch möglich, das CSS Paint Polyfill zu verwenden, das modernen Browsern Unterstützung für CSS Custom Paint und Paint Worklets hinzufügt.
Anwendungsfälle
Es gibt viele Anwendungsfälle für Paint Worklets, einige davon sind offensichtlicher als andere. Eine der offensichtlicheren Möglichkeiten ist die Verwendung von Paint Worklet, um die Größe Ihres DOM zu reduzieren. Oft werden Elemente nur hinzugefügt, um mit CSS Verzierungen zu erstellen. In Material Design Lite enthält die Schaltfläche mit dem Welleneffekt beispielsweise zwei zusätzliche <span>
-Elemente, um die Welle zu implementieren. Wenn Sie viele Schaltflächen haben, kann das zu einer großen Anzahl von DOM-Elementen führen und die Leistung auf Mobilgeräten beeinträchtigen. Wenn Sie den Wellen-Effekt stattdessen mit einem Paint-Worklet implementieren, erhalten Sie 0 zusätzliche Elemente und nur ein Paint-Worklet.
Außerdem haben Sie etwas, das sich viel einfacher anpassen und parametrisieren lässt.
Ein weiterer Vorteil der Verwendung von Paint Worklet besteht darin, dass eine Lösung mit Paint Worklet in den meisten Fällen nur wenige Bytes umfasst. Das hat natürlich auch Nachteile: Ihr Paint-Code wird immer dann ausgeführt, wenn sich die Größe des Canvas oder einer der Parameter ändert. Wenn Ihr Code komplex ist und lange dauert, kann es zu Rucklern kommen. Chrome arbeitet daran, Paint-Worklets aus dem Haupt-Thread zu entfernen, damit auch lang laufende Paint-Worklets die Reaktionsfähigkeit des Haupt-Threads nicht beeinträchtigen.
Am spannendsten finde ich, dass Paint Worklet ein effizientes Polyfilling von CSS-Funktionen ermöglicht, die ein Browser noch nicht unterstützt. Ein Beispiel wäre, konische Verläufe zu polyfillen, bis sie nativ in Chrome verfügbar sind. Ein weiteres Beispiel: Bei einem CSS-Treffen wurde beschlossen, dass Sie jetzt mehrere Rahmenfarben verwenden können. Während dieser Besprechung hat mein Kollege Ian Kilpatrick ein Polyfill für dieses neue CSS-Verhalten mit einem Paint-Worklet geschrieben.
Über den Tellerrand schauen
Die meisten denken an Hintergrundbilder und Rahmenbilder, wenn sie von Paint Worklet hören. Ein weniger intuitiver Anwendungsfall für Paint Worklet ist mask-image
, um DOM-Elemente in beliebigen Formen darzustellen. Beispiel für einen Diamanten:

mask-image
nimmt ein Bild an, das die Größe des Elements hat. In Bereichen, in denen das Maskenbild transparent ist, ist auch das Element transparent. In Bereichen, in denen das Maskenbild undurchsichtig ist, ist auch das Element undurchsichtig.
Jetzt in Chrome
Das Paint-Worklet ist schon seit einiger Zeit in Chrome Canary verfügbar. In Chrome 65 ist die Funktion standardmäßig aktiviert. Probieren Sie die neuen Möglichkeiten aus, die Paint Worklet bietet, und zeigen Sie uns, was Sie damit entwickelt haben. Hier findest du weitere Inspirationen.