Nuove possibilità in Chrome 65
L'API CSS Paint (nota anche come "CSS Custom Paint" o "Worklet di pittura di Houdini") è attivata per impostazione predefinita a partire da Chrome 65. Che cos'è? Cosa puoi fare con questo strumento? E come funziona? Continua a leggere…
L'API CSS Paint consente di generare un'immagine tramite programmazione ogni volta che una proprietà CSS si aspetta un'immagine. Proprietà come background-image
o border-image
vengono in genere utilizzate con url()
per caricare un file immagine o con le funzioni predefinite del CSS come linear-gradient()
. Ora, invece di utilizzare questi valori, puoi usare paint(myPainter)
per fare riferimento a un worklet di pittura.
Scrivere un worklet di Paint
Per definire un worklet di pittura denominato myPainter
, dobbiamo caricare un file worklet di pittura CSS utilizzando CSS.paintWorklet.addModule('my-paint-worklet.js')
. In questo
file, possiamo utilizzare la funzione registerPaint
per registrare una classe di worklet di pittura:
class MyPainter {
paint(ctx, geometry, properties) {
// ...
}
}
registerPaint('myPainter', MyPainter);
All'interno del callback paint()
, possiamo utilizzare ctx
nello stesso modo in cui useremmo un
CanvasRenderingContext2D
come lo conosciamo da <canvas>
. Se sai come
disegnare in un <canvas>
, puoi farlo anche in un worklet di pittura. geometry
ci indica la larghezza e l'altezza della tela a nostra disposizione. properties
Lo spiegherò più avanti in questo articolo.
Come esempio introduttivo, scriviamo un worklet di pittura a scacchi e lo utilizziamo come immagine di sfondo di un <textarea>
. (Utilizzo un'area di testo perché è ridimensionabile per impostazione predefinita):
<!-- 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);
Se hai già utilizzato <canvas>
in passato, questo codice dovrebbe esserti familiare. Guarda la demo dal vivo qui.
La differenza rispetto all'utilizzo di un'immagine di sfondo comune è che il motivo verrà ridisegnato su richiesta ogni volta che l'utente ridimensiona la textarea. Ciò significa che l'immagine di sfondo è sempre esattamente delle dimensioni necessarie, inclusa la compensazione per i display ad alta densità.
È fantastico, ma è anche piuttosto statico. Dovremmo scrivere un nuovo worklet ogni volta che vogliamo lo stesso motivo, ma con quadrati di dimensioni diverse? La risposta è no.
Parametrizzare il worklet
Fortunatamente, il worklet di pittura può accedere ad altre proprietà CSS, ed è qui che entra in gioco il
parametro aggiuntivo properties
. Se assegni al corso un attributo statico inputProperties
, puoi iscriverti alle modifiche di qualsiasi proprietà CSS, incluse le proprietà personalizzate. I valori ti verranno forniti tramite il parametroproperties
.
<!-- 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);
Ora possiamo utilizzare lo stesso codice per tutti i diversi tipi di scacchiera. Ma c'è di più: ora possiamo andare in DevTools e modificare i valori fino a trovare l'aspetto giusto.
Browser che non supportano il worklet di pittura
Al momento della stesura di questo articolo, solo Chrome ha implementato il worklet di pittura. Anche se esistono indicatori positivi da parte di tutti gli altri fornitori di browser, non si sono registrati molti progressi. Per non perderti nessuna novità, consulta regolarmente la pagina Is Houdini Ready Yet?. Nel frattempo, assicurati di utilizzare il miglioramento progressivo per mantenere in esecuzione il codice anche se non è supportato il worklet di pittura. Per assicurarti che tutto funzioni come previsto, devi modificare il codice in due punti: CSS e JS.
Per rilevare il supporto del worklet di pittura in JS, puoi controllare l'oggetto CSS
:
js
if ('paintWorklet' in CSS) {
CSS.paintWorklet.addModule('mystuff.js');
}
Per quanto riguarda il CSS, hai due opzioni. Puoi utilizzare @supports
:
@supports (background: paint(id)) {
/* ... */
}
Un trucco più compatto consiste nell'utilizzare il fatto che il CSS convalida e successivamente ignora un'intera dichiarazione di proprietà se contiene una funzione sconosciuta. Se specifichi una proprietà due volte, prima senza il worklet di pittura e poi con il worklet di pittura, ottieni il miglioramento progressivo:
textarea {
background-image: linear-gradient(0, red, blue);
background-image: paint(myGradient, red, blue);
}
Nei browser con supporto per il worklet di pittura, la seconda dichiarazione di
background-image
sovrascriverà la prima. Nei browser senza supporto per il worklet di pittura, la seconda dichiarazione non è valida e verrà ignorata, lasciando in vigore la prima dichiarazione.
CSS Paint Polyfill
Per molti utilizzi, è anche possibile utilizzare il CSS Paint Polyfill, che aggiunge il supporto di CSS Custom Paint e Paint Worklet ai browser moderni.
Casi d'uso
Esistono molti casi d'uso per i worklet di pittura, alcuni più evidenti di altri. Uno dei più evidenti è l'utilizzo del worklet di pittura per ridurre le dimensioni del DOM. Spesso gli elementi vengono aggiunti solo per creare abbellimenti
utilizzando il CSS. Ad esempio, in Material Design Lite il pulsante con l'effetto ripple contiene altri due elementi <span>
per implementare l'effetto stesso. Se hai molti pulsanti, il numero di elementi DOM può aumentare notevolmente e le prestazioni su dispositivi mobili possono peggiorare. Se invece implementi l'effetto ripple utilizzando il worklet di pittura, ottieni 0 elementi aggiuntivi e un solo worklet di pittura.
Inoltre, hai a disposizione un elemento molto più facile da personalizzare e parametroizzare.
Un altro vantaggio dell'utilizzo del worklet di pittura è che, nella maggior parte dei casi, una soluzione che lo utilizza è di piccole dimensioni in termini di byte. Ovviamente, c'è un compromesso: il codice di pittura verrà eseguito ogni volta che le dimensioni della tela o uno dei parametri cambiano. Pertanto, se il codice è complesso e richiede molto tempo, potrebbe introdurre ritardi. Chrome sta lavorando per spostare i worklet di pittura dal thread principale in modo che anche quelli di lunga durata non influiscano sulla reattività del thread principale.
Per me, la prospettiva più entusiasmante è che il worklet di pittura consente un polyfilling efficiente delle funzionalità CSS che un browser non ha ancora. Un esempio potrebbe essere implementare il polyfill per le sfumature coniche finché non vengono implementate in modo nativo in Chrome. Un altro esempio: in una riunione CSS è stato deciso che ora puoi avere più colori di bordo. Mentre la riunione era ancora in corso, il mio collega Ian Kilpatrick ha scritto un polyfill per questo nuovo comportamento CSS utilizzando il worklet di pittura.
Pensare fuori dagli schemi
La maggior parte delle persone inizia a pensare alle immagini di sfondo e ai bordi quando scopre il worklet di pittura. Un caso d'uso meno intuitivo per il worklet di pittura è
mask-image
dare agli elementi DOM forme arbitrarie. Ad esempio un
diamante:
mask-image
acquisisce un'immagine delle dimensioni dell'elemento. Le aree in cui l'immagine della maschera è trasparente, l'elemento è trasparente. Aree in cui l'immagine della maschera è opaca, l'elemento opaco.
Ora su Chrome
Il worklet di pittura è disponibile in Chrome Canary da un po' di tempo. In Chrome 65 è attivata per impostazione predefinita. Prova le nuove possibilità offerte dal worklet di Paint e mostraci cosa hai creato. Per ulteriori ispirazioni, consulta la collezione di Vincent De Oliveira.