CSS Paint API

Kemungkinan baru di Chrome 65

CSS Paint API (juga dikenal sebagai "CSS Custom Paint" atau "Houdini's paint worklet") diaktifkan secara default mulai Chrome 65. Fitur apa ini? Apa yang dapat Anda lakukan dengan hal tersebut? Dan bagaimana cara kerjanya? Yah, silakan baca terus, sampai jumpa...

CSS Paint API memungkinkan Anda membuat gambar secara terprogram setiap kali properti CSS mengharapkan gambar. Properti seperti background-image atau border-image biasanya digunakan dengan url() untuk memuat file gambar atau dengan fungsi bawaan CSS seperti linear-gradient(). Daripada menggunakannya, kini Anda dapat menggunakan paint(myPainter) untuk mereferensikan worklet cat.

Menulis worklet cat

Untuk menentukan worklet cat yang disebut myPainter, kita perlu memuat file worklet cat CSS menggunakan CSS.paintWorklet.addModule('my-paint-worklet.js'). Dalam file tersebut, kita dapat menggunakan fungsi registerPaint untuk mendaftarkan class worklet cat:

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

registerPaint('myPainter', MyPainter);

Di dalam callback paint(), kita dapat menggunakan ctx dengan cara yang sama seperti CanvasRenderingContext2D seperti yang kita ketahui dari <canvas>. Jika mengetahui cara menggambar <canvas>, Anda dapat menggambar di worklet cat. geometry memberi tahu kita lebar dan tinggi kanvas yang kita inginkan. properties Saya akan menjelaskannya nanti dalam artikel ini.

Sebagai contoh pengantar, mari kita tulis worklet cat kotak-kotak dan gunakan sebagai gambar latar <textarea>. (Saya menggunakan area teks karena secara default dapat diubah ukurannya.):

<!-- 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);

Jika Anda pernah menggunakan <canvas> sebelumnya, kode ini seharusnya tidak asing. Lihat demo langsung di sini.

Textarea dengan pola kotak-kotak sebagai gambar latar
Textarea dengan pola kotak-kotak sebagai gambar latar.

Perbedaan dari penggunaan gambar latar umum di sini adalah pola akan digambar ulang sesuai permintaan, setiap kali pengguna mengubah ukuran area teks. Ini berarti gambar latar akan selalu sebesar yang diperlukan, termasuk kompensasi untuk layar berkepadatan tinggi.

Cukup bagus, tetapi juga cukup statis. Apakah kita ingin menulis worklet baru setiap kali kita menginginkan pola yang sama tetapi dengan ukuran kotak yang berbeda? Jawabannya adalah tidak.

Memparameterisasi worklet

Untungnya, worklet paint dapat mengakses properti CSS lainnya, yang merupakan tempat parameter tambahan properties digunakan. Dengan memberi class atribut inputProperties statis, Anda dapat berlangganan perubahan pada properti CSS apa pun, termasuk properti kustom. Nilai akan diberikan kepada Anda melalui parameter 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);

Sekarang kita dapat menggunakan kode yang sama untuk semua jenis papan catur yang berbeda. Namun, yang lebih bagus lagi, sekarang kita bisa masuk ke DevTools dan mengenali nilai-nilai sampai menemukan tampilan yang tepat.

Browser yang tidak mendukung worklet paint

Pada saat penulisan ini, hanya Chrome yang telah mengimplementasikan worklet cat. Meskipun ada sinyal positif dari semua vendor browser lainnya, tidak ada banyak kemajuan. Untuk mendapatkan info terbaru, periksa Is Houdini Ready Yet? secara berkala. Sementara itu, pastikan untuk menggunakan peningkatan progresif agar kode Anda tetap berjalan meskipun tidak ada dukungan untuk worklet cat. Untuk memastikan semuanya berfungsi seperti yang diharapkan, Anda harus menyesuaikan kode di dua tempat: CSS dan JS.

Mendeteksi dukungan untuk pekerjaan cat di JS dapat dilakukan dengan memeriksa objek CSS: js if ('paintWorklet' in CSS) { CSS.paintWorklet.addModule('mystuff.js'); } Untuk sisi CSS, Anda memiliki dua opsi. Anda dapat menggunakan @supports:

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

Trik yang lebih sederhana adalah menggunakan fakta bahwa CSS membatalkan validasi, lalu mengabaikan seluruh deklarasi properti jika ada fungsi yang tidak diketahui di dalamnya. Jika Anda menentukan properti dua kali — pertama tanpa worklet cat, lalu dengan worklet cat — Anda akan mendapatkan progressive enhancement:

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

Di browser dengan dukungan untuk worklet paint, deklarasi kedua background-image akan menimpa deklarasi pertama. Di browser tanpa dukungan untuk worklet paint, deklarasi kedua tidak valid dan akan dihapus, sehingga deklarasi pertama tetap berlaku.

Polyfill Cat CSS

Untuk berbagai penggunaan, Anda juga dapat menggunakan CSS Paint Polyfill, yang menambahkan dukungan Worklet Paint dan Paint Kustom CSS ke browser modern.

Kasus penggunaan

Ada banyak kasus penggunaan untuk worklet cat, beberapa di antaranya lebih jelas daripada yang lain. Salah satu yang lebih jelas adalah menggunakan paint worklet untuk mengurangi ukuran DOM Anda. Sering kali, elemen ditambahkan hanya untuk membuat hiasan menggunakan CSS. Misalnya, di Material Design Lite, tombol dengan efek ripple berisi 2 elemen <span> tambahan untuk menerapkan ripple itu sendiri. Jika Anda memiliki banyak tombol, ini dapat mencapai jumlah elemen DOM yang cukup banyak dan dapat menyebabkan penurunan performa di perangkat seluler. Jika Anda mengimplementasikan efek riak menggunakan worklet cat, Anda akan mendapatkan 0 elemen tambahan dan hanya satu worklet cat. Selain itu, Anda memiliki sesuatu yang jauh lebih mudah untuk disesuaikan dan diparameterisasi.

Keuntungan lain dari penggunaan worklet paint adalah, dalam sebagian besar skenario, solusi yang menggunakan worklet cat berukuran kecil dalam hal byte. Tentu saja, ada konsekuensinya: kode cat Anda akan dijalankan setiap kali ukuran kanvas atau parameter apa pun berubah. Jadi, jika kode Anda kompleks dan memakan waktu lama, hal tersebut dapat menimbulkan jank. Chrome sedang berupaya memindahkan worklet cat dari thread utama agar worklet cat yang berjalan lama tidak memengaruhi responsivitas thread utama.

Bagi saya, prospek yang paling menarik adalah worklet paint memungkinkan polyfill fitur CSS yang efisien yang belum dimiliki browser. Salah satu contohnya adalah untuk mem-polyfill gradien kerucut hingga tiba di Chrome secara native. Contoh lain: dalam rapat CSS, diputuskan bahwa kini Anda dapat memiliki beberapa warna batas. Sementara rapat ini masih berlangsung, rekan saya Ian Kilpatrick menulis polyfill untuk perilaku CSS baru ini menggunakan worklet paint.

Berpikir kreatif

Kebanyakan orang mulai memikirkan gambar latar dan gambar pembatas saat mereka mempelajari worklet cat. Satu kasus penggunaan yang kurang intuitif untuk worklet paint adalah mask-image untuk membuat elemen DOM memiliki bentuk arbitrer. Misalnya belah ketupat:

Elemen DOM berbentuk berlian.
Elemen DOM berbentuk berlian.

mask-image mengambil gambar yang merupakan ukuran elemen. Area tempat gambar mask transparan, elemennya transparan. Area tempat gambar mask buram, elemen buram.

Sekarang di Chrome

Paint telah ada di Chrome Canary selama beberapa waktu. Dengan Chrome 65, fitur ini diaktifkan secara default. Silakan coba berbagai kemungkinan baru yang akan terbuka dan tunjukkan apa yang telah Anda buat. Untuk mendapatkan inspirasi lainnya, lihat koleksi Vincent De Oliveira.