Nuove possibilità in Chrome 65
L'API CSS Paint (nota anche come "CSS Custom Paint" o "Houdini's paint worklet") è attiva per impostazione predefinita a partire da Chrome 65. Di cosa si tratta? Che cosa puoi fare? E come funziona? Continua a leggere...
L'API CSS Paint ti consente di generare in modo programmatico un'immagine ogni volta che una proprietà CSS prevede un'immagine. In genere, proprietà come background-image
o border-image
vengono utilizzate con url()
per caricare un file immagine o con funzioni incorporate di CSS come linear-gradient()
. Invece di utilizzarli, ora puoi usare paint(myPainter)
per fare riferimento a un worklet di colorazione.
Scrivere un worklet di colorazione
Per definire un worklet di colorazione denominato myPainter
, dobbiamo caricare un file di worklet di colorazione CSS utilizzando CSS.paintWorklet.addModule('my-paint-worklet.js')
. In questo file, possiamo utilizzare la funzione registerPaint
per registrare una classe di worklet di colorazione:
class MyPainter {
paint(ctx, geometry, properties) {
// ...
}
}
registerPaint('myPainter', MyPainter);
All'interno del callback paint()
, possiamo utilizzare ctx
come faresti con un
CanvasRenderingContext2D
come lo conosciamo da <canvas>
. Se sai come disegnare con un <canvas>
, puoi disegnare un worklet! geometry
indica la
larghezza e l'altezza della tela a nostra disposizione. properties
Ti spiegheremo
più avanti in questo articolo.
Come esempio introduttivo, scriviamo un worklet di pittura a scacchiera e utilizziamolo come immagine di sfondo di un <textarea>
. (sto usando 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 utilizzato <canvas>
in passato, il codice dovrebbe esserti familiare. Guarda la demo dal vivo qui.
La differenza rispetto all'utilizzo di un'immagine di sfondo comune in questo caso è che il motivo verrà ridisegnato su richiesta, ogni volta che l'utente ridimensiona l'area di testo. Ciò significa che l'immagine di sfondo ha sempre le dimensioni necessarie, compresa la compensazione per i display ad alta densità.
Non male, ma è anche statico. Dovremmo scrivere un nuovo worklet ogni volta che vogliamo lo stesso pattern, ma con quadrati di dimensioni diverse? La risposta è no.
Parametrizzazione del worklet
Fortunatamente, il worklet di colorazione può accedere ad altre proprietà CSS, qui che entra in gioco il
parametro aggiuntivo properties
. Se assegni alla classe un attributo inputProperties
statico, puoi iscriverti alle modifiche a qualsiasi proprietà CSS, incluse le proprietà personalizzate. I valori ti verranno assegnati tramite il parametro properties
.
<!-- 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 soprattutto, ora possiamo usare DevTools e giocare ai valori fino a trovare il look giusto.
Browser che non supportano il worklet di colorazione
Al momento della stesura di questo documento, solo Chrome ha implementato il worklet Paint. Sebbene esistano segnali positivi da parte di tutti gli altri fornitori di browser, non ci sono molti progressi. Per tenerti al corrente, controlla regolarmente la sezione Is Houdini Ready Yet?. Nel frattempo, assicurati di utilizzare il miglioramento progressivo per mantenere il codice in esecuzione anche se non è disponibile il supporto per il worker Paint. Per assicurarti che tutto funzioni come previsto, devi modificare il codice in due punti: il CSS e il codice JS.
Il rilevamento del supporto del worklet di colorazione in JS può essere eseguito controllando l'oggetto CSS
:
js
if ('paintWorklet' in CSS) {
CSS.paintWorklet.addModule('mystuff.js');
}
Per il lato CSS, hai due opzioni. Puoi utilizzare @supports
:
@supports (background: paint(id)) {
/* ... */
}
Un trucco più compatto è utilizzare il fatto che CSS invalida e successivamente ignora un'intera dichiarazione di proprietà se è presente una funzione sconosciuta. Se specifichi una proprietà due volte, prima senza il worklet di colorazione e poi con il worklet di colorazione, ottieni un miglioramento progressivo:
textarea {
background-image: linear-gradient(0, red, blue);
background-image: paint(myGradient, red, blue);
}
Nei browser con supporto per il worklet Paint, la seconda dichiarazione di
background-image
sovrascriverà la prima. Nei browser senza supporto per il worklet di colorazione, la seconda dichiarazione non è valida e verrà ignorata, lasciando attiva la prima dichiarazione.
Pittura CSS Polyfill
Per molti utilizzi, puoi anche utilizzare CSS Paint Polyfill, che aggiunge ai browser moderni il supporto CSS Custom Paint e Paint.
Casi d'uso
Esistono molti casi d'uso per i worklet di pittura, alcuni dei quali più evidenti di altri. Uno dei più evidenti è l'utilizzo di un worklet di colorazione per ridurre le dimensioni
del DOM. Spesso, gli elementi vengono aggiunti esclusivamente per creare abbellimenti
utilizzando CSS. Ad esempio, in Material Design Lite il pulsante con l'effetto Onde contiene due elementi <span>
aggiuntivi per implementare l'eco stesso. La presenza di molti pulsanti può causare la somma di numerosi
elementi DOM e un peggioramento delle prestazioni sui dispositivi mobili. Se invece implementi l'effetto a onde utilizzando il worklet di colorazione, ottieni 0 elementi aggiuntivi e un solo worklet di colorazione.
Inoltre, c'è qualcosa che è molto più facile da personalizzare
e parametrizzare.
Un altro vantaggio dell'utilizzo del worklet di colorazione è che, nella maggior parte degli scenari, una soluzione che utilizza il worklet di colorazione è piccola in termini di byte. Naturalmente, c'è un compromesso: il codice viene eseguito ogni volta che le dimensioni della tela o dei parametri cambiano. Pertanto, se il tuo codice è complesso e richiede molto tempo, potrebbe introdurre jank. Chrome sta lavorando allo spostamento dei worklet di colorazione dal thread principale in modo che anche quelli di colorazione a lunga esecuzione non influiscano sulla reattività del thread principale.
Secondo me, la prospettiva più entusiasmante è che il worklet di colorazione consente un polyfill efficiente delle funzionalità CSS di cui un browser non dispone ancora. Un esempio potrebbe essere il polyfill dei gradienti conici finché non arrivano in Chrome in modo nativo. Un altro esempio: durante una riunione CSS, si è deciso che ora puoi avere più colori per il bordo. Mentre l'incontro era ancora in corso, il mio collega Ian Kilpatrick ha scritto un polyfill per questo nuovo comportamento CSS utilizzando un worklet di colorazione.
Pensare fuori dagli schemi
La maggior parte delle persone inizia a pensare alle immagini di sfondo e alle immagini dei bordi quando
impara a vedere il worklet di colorazione. Un caso d'uso meno intuitivo per il worklet di colorazione è
mask-image
, che consente di fare in modo che gli elementi DOM abbiano forme arbitrarie. Ad esempio, un
diamante:
mask-image
acquisisce un'immagine che corrisponda alle dimensioni dell'elemento. Aree in cui l'immagine della maschera è trasparente, l'elemento è trasparente. Aree in cui l'immagine della maschera
è opaca, l'elemento è opaco.
Ora in Chrome
Colorazione del worklet è stata utilizzata per un po' di tempo in Chrome Canary. Con Chrome 65, è attivo per impostazione predefinita. Prova le nuove possibilità che si aprono sul worklet di pittura e mostraci cosa hai creato. Per ulteriori spunti, dai un'occhiata alla collezione di Vincent De Oliveira.