API CSS Paint

Nuove possibilità in Chrome 65

L'API CSS Paint (nota anche come "CSS Custom Paint" o "Houdini's paint worklet") è attivate per impostazione predefinita a partire da Chrome 65. Che cos'è? 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 un CSS prevede un'immagine. Proprietà come background-image o border-image vengono generalmente utilizzati con url() per caricare un file immagine o con CSS integrato 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 worklet CSS utilizzando CSS.paintWorklet.addModule('my-paint-worklet.js'). In questo possiamo utilizzare la funzione registerPaint per registrare una classe di worklet di colorazione:

class MyPainter {
  paint(ctx, geometry, properties) {
    // ...
  }
}

registerPaint('myPainter', MyPainter);

Nel callback paint(), possiamo utilizzare ctx nello stesso modo in cui CanvasRenderingContext2D come lo conosciamo da <canvas>. Se sai come disegna in un <canvas>, puoi disegnare in un worklet! geometry indica e l'altezza della tela a nostra disposizione. properties Lo farò più avanti in questo articolo.

Come esempio introduttivo, passiamo a scrivere un foglio di lavoro sulla vernice a scacchiera e usarlo come immagine di sfondo di un <textarea>. (Uso un'area di testo perché ridimensionabili 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. Consulta dal vivo dimostrazione qui.

Area di testo con un motivo a scacchiera come immagine di sfondo
Area di testo con un motivo a scacchiera come immagine di sfondo.

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 l'immagine di sfondo sia sempre grande quanto deve essere, inclusa la di compensazione per i display ad alta densità.

Non male, ma è anche statico. Dovremmo scrivere un nuovo un worklet ogni volta che volevamo lo stesso motivo, ma con dimensioni diverse quadrati? La risposta è no.

Parametrizzazione del worklet

Fortunatamente, il worklet di colorazione può accedere ad altre proprietà CSS, dove è possibile entra in gioco il parametro aggiuntivo properties. Assegnando alla classe un'immagine inputProperties, puoi iscriverti alle modifiche a qualsiasi proprietà CSS, incluse le proprietà personalizzate. I valori ti verranno forniti tramite 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 anche meglio, ora possiamo entrare in DevTools e giocare sui 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. Mentre eri in sono segnali positivi di tutti gli altri fornitori di browser, non ci sono molti progressi. Per restare al passo con gli aggiornamenti, controlla Is Houdini Ready Yet? regolarmente. Nel frattempo, assicurati di usare il formato progressivo miglioramento per mantenere il codice in esecuzione anche se non è supportato un worklet. Per assicurarti che tutto funzioni come previsto, devi modificare il codice in due posizioni: il CSS e il codice JS.

Il rilevamento del supporto del worklet di colorazione in JS può essere eseguito selezionando l'oggetto CSS: js if ('paintWorklet' in CSS) { CSS.paintWorklet.addModule('mystuff.js'); } Per quanto riguarda CSS, hai due opzioni. Puoi utilizzare @supports:

@supports (background: paint(id)) {
  /* ... */
}

Un trucco più compatto consiste nell'utilizzare il fatto che CSS invalida e successivamente ignora un'intera dichiarazione della proprietà se contiene una funzione sconosciuta. Se specifichi una proprietà due volte: prima senza il worklet Paint e poi con di colorazione, si ottiene un miglioramento progressivo:

textarea {
  background-image: linear-gradient(0, red, blue);
  background-image: paint(myGradient, red, blue);
}

Nei browser che supportano il worklet "paint", la seconda dichiarazione background-image sovrascriverà la prima. Nei browser senza supporto per il worklet Paint, la seconda dichiarazione non è valida e verrà eliminata, lasciando in vigore la prima dichiarazione.

Pittura CSS Polyfill

Per molti utilizzi, è anche possibile usare Polyfill per vernice CSS, che aggiunge il supporto CSS Custom Paint and Paints ai browser moderni.

Casi d'uso

Esistono molti casi d'uso per i worklet di pittura, alcuni dei quali più evidenti altri. Una delle più evidenti è l'uso di un worklet di colorazione per ridurne 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 a onde contiene altri due elementi <span> per implementare ondeggiare. La presenza di molti pulsanti può determinare un bel numero di elementi DOM e può portare a un peggioramento delle prestazioni sui dispositivi mobili. Se implementare l'effetto onde usando un worklet di colorazione al contrario, ci sono 0 elementi aggiuntivi e solo un worklet di colorazione. Inoltre, si può avere qualcosa di molto più facile da personalizzare parametrizzare.

Un altro vantaggio dell'utilizzo di un worklet di colorazione è che, nella maggior parte degli scenari, una soluzione l'utilizzo del worklet di colorazione è ridotto in termini di byte. Ovviamente, compromesso: il codice verrà eseguito ogni volta che le dimensioni della tela o uno qualsiasi dei vengono modificati i parametri. Quindi se il tuo codice è complesso e richiede molto tempo, potrebbe introdurre jank. Chrome si sta adoperando per spostare i worklet di colorazione dal thread principale in modo da anche i lavori di pittura a lunga durata non influiscono sulla reattività del .

Secondo me, la prospettiva più entusiasmante è che il worklet di colorazione consente una il polyfill delle funzionalità CSS di cui un browser non dispone ancora. Un esempio potrebbe essere per eseguire il polyfill dei gradienti conici fino a quando arrivano in Chrome in modo nativo. Un altro esempio: in una riunione CSS, che ora puoi avere più colori per i bordi. Mentre la riunione era ancora in corso, il mio collega Ian Kilpatrick ha scritto un polyfill per il nuovo CSS utilizzando il 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 scopri di più sul worklet di colorazione. Un caso d'uso meno intuitivo per il worklet di colorazione è mask-image per fare in modo che gli elementi DOM abbiano forme arbitrarie. Ad esempio, un diamante:

Un elemento DOM a forma di rombo.
. Un elemento DOM a forma di rombo.

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 viene applicata la maschera l'immagine è opaca, mentre l'elemento è opaco.

Ora in Chrome

Colorazione del worklet è stata utilizzata per un po' di tempo in Chrome Canary. Con Chrome 65, sono abilitate per impostazione predefinita. Prova le nuove possibilità si apre il worklet del dipinto, che ci mostra cosa hai costruito! Per ulteriore ispirazione, dai un'occhiata alla collezione di Vincent De Oliveira.