Nuove possibilità in Chrome 65
L'API CSS Paint (nota anche come "CSS Custom Paint" o "Houdini's Paint worklet") è abilitata per impostazione predefinita a partire da Chrome 65. Di cosa si tratta? Cosa puoi farne? E come funziona? Continua a leggere...
L'API CSS Paint ti consente di generare un'immagine in modo programmatico ogni volta che una proprietà CSS
desidera un'immagine. Proprietà come background-image
o border-image
di solito vengono utilizzate con url()
per caricare un file immagine o con funzioni CSS integrate
come linear-gradient()
. Anziché utilizzare questi elementi, ora puoi usare paint(myPainter)
per fare riferimento a un worklet di disegno.
Scrittura di un worklet
Per definire un worklet paint denominato myPainter
, dobbiamo caricare un file paint
worklet CSS utilizzando CSS.paintWorklet.addModule('my-paint-worklet.js')
. In questo
file, possiamo utilizzare la funzione registerPaint
per registrare una classe di worklet di paint:
class MyPainter {
paint(ctx, geometry, properties) {
// ...
}
}
registerPaint('myPainter', MyPainter);
All'interno del callback paint()
, possiamo utilizzare ctx
come faresti con CanvasRenderingContext2D
come lo conosciamo da <canvas>
. Se sai come disegnare in <canvas>
, puoi disegnare in un worklet di colorazione. geometry
indica la
larghezza e l'altezza della tela a nostra disposizione. properties
Lo
parlerò più avanti in questo articolo.
Come esempio introduttivo, scriviamo un worklet per colorare la scacchiera e usiamolo
come immagine di sfondo di un elemento <textarea>
. (Uso 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, questo codice dovrebbe esserti familiare. Guarda la demo dal vivo qui.
La differenza rispetto all'uso di un'immagine di sfondo comune in questo caso è che il pattern viene ridisegnato su richiesta, ogni volta che l'utente ridimensiona l'area di testo. Ciò significa che l'immagine di sfondo è sempre esattamente grande quanto deve essere, inclusa la compensazione per i display ad alta densità.
È interessante, ma è anche piuttosto statico. Vogliamo scrivere un nuovo worklet ogni volta che volevamo lo stesso pattern ma con quadrati di dimensioni diverse? La risposta è no.
Parametrizzare il worklet
Fortunatamente, il worklet di Paint può accedere ad altre proprietà CSS, ed è qui che entra in gioco il parametro aggiuntivo properties
. Se assegni alla classe un attributo inputProperties
statico, puoi richiedere di apportare 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 ancora meglio, ora possiamo entrare in DevTools e giocare con i valori fino a trovare l'aspetto giusto.
Browser che non supportano il worklet di paint
Al momento della scrittura, solo Chrome ha implementato il worklet di paint. Anche se ci sono indicatori positivi da parte di tutti gli altri fornitori di browser, non c'è molto progresso. Per ricevere aggiornamenti, seleziona regolarmente Houdini pronto?. Nel frattempo, assicurati di utilizzare il miglioramento progressivo per mantenere il codice in esecuzione anche se non è supportato il worklet di Paint. Per assicurarti che tutto funzioni come previsto, devi modificare il codice in due posizioni: nel CSS e JS.
Puoi rilevare il supporto del worklet di colorazione in JavaScript 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 consiste nell'utilizzare il fatto che il CSS invalida e successivamente ignora l'intera dichiarazione di una proprietà se contiene una funzione sconosciuta. Se specifichi una proprietà due volte, prima senza worklet di paint e poi con il worklet di colorazione, ottieni il miglioramento progressivo:
textarea {
background-image: linear-gradient(0, red, blue);
background-image: paint(myGradient, red, blue);
}
Nei browser che supportano il worklet di colorazione, la seconda dichiarazione di background-image
sovrascrive la prima. Nei browser senza supporto per il worklet paint, la seconda dichiarazione non è valida e verrà eliminata, lasciando in vigore la prima dichiarazione.
Polyfill della vernice CSS
Per molti utilizzi, è possibile utilizzare anche il CSS Paint Polyfill, che aggiunge il supporto dei Worklet CSS Custom Paint e Paint ai browser moderni.
Casi d'uso
Esistono molti casi d'uso per i worklet di colorazione, alcuni dei quali sono più evidenti di altri. Una delle più evidenti è l'utilizzo del worklet di colorazione per ridurre le dimensioni del DOM. Spesso gli elementi vengono aggiunti unicamente per creare abbellimenti utilizzando CSS. Ad esempio, in Material Design Lite il pulsante
con l'effetto ondulazione contiene altri 2 elementi <span>
per implementare
l'onda stessa. Se sono presenti molti pulsanti, questa operazione può aggiungere fino a un certo numero di elementi DOM e portare a un peggioramento delle prestazioni sui dispositivi mobili. Se implementi l'effetto onde utilizzando il worklet di colorazione, il risultato è 0 elementi aggiuntivi e un solo worklet di colorazione.
Inoltre, sono disponibili elementi molto più facili da personalizzare
e parametrizzare.
Un altro vantaggio dell'utilizzo del worklet di Paint è che, nella maggior parte degli scenari, una soluzione che utilizza il worklet di color è piccola in termini di byte. Ovviamente esiste un compromesso: il codice di colorazione viene eseguito ogni volta che le dimensioni della tela o uno qualsiasi dei parametri cambiano. Quindi, se il tuo codice è complesso e richiede molto tempo, potrebbe introdurre Jank. Chrome sta cercando di spostare i worklet di Paint dal thread principale in modo che anche i worklet di Paint di lunga durata non influiscano sulla reattività del thread principale.
Per me, la prospettiva più entusiasmante è che il worklet di paint consente un efficiente polyfill delle funzionalità CSS che un browser non dispone ancora. Ad esempio, puoi eseguire il polyfill di gradienti conici finché non arrivano in Chrome in modo nativo. Un altro esempio: in una riunione CSS, si è deciso di avere più colori per i bordi. Mentre questo incontro era ancora in corso, il mio collega Ian Kilpatrick ha scritto un polyfill per questo nuovo comportamento CSS utilizzando il worklet di Paint.
Pensare fuori dagli schemi
Quando imparano a colorare il worklet, la maggior parte delle persone inizia a pensare alle immagini di sfondo e ai bordi. Un caso d'uso meno intuitivo per il worklet di colorazione è
mask-image
per rendere gli elementi DOM con forme arbitrarie. Ad esempio un diamante:
mask-image
acquisisce un'immagine che ha le stesse dimensioni dell'elemento. Aree in cui l'immagine della maschera è trasparente e l'elemento è trasparente. Le aree in cui l'immagine della maschera
è opaca, mentre l'elemento è opaco.
Ora in Chrome
Il worklet di colorazione è disponibile in Chrome Canary da un po' di tempo. In Chrome 65 è attivo per impostazione predefinita. Vai avanti e prova le nuove possibilità che si apre sul worklet di Paint e mostraci cosa hai creato. Per ulteriore ispirazione, dai un'occhiata alla collezione di Vincent De Oliveira.