Chrome 65 新增無限可能
自 Chrome 65 版起,系統預設會啟用 CSS Paint API (又稱「CSS 自訂繪製功能」或「Houdini 油漆工」)。是什麼?你可以如何運用?運作方式繼續往下看吧...」
CSS Paint API 可讓您在 CSS 屬性預期圖片時,透過程式輔助方式產生圖片。background-image
或 border-image
等屬性通常會與 url()
搭配使用,用於載入圖片檔或 linear-gradient()
等 CSS 內建函式。您現在可以使用 paint(myPainter)
來參照繪製工作小程式,而不使用這些項目。
創作顏料畫
如要定義名為 myPainter
的油漆廠,我們必須使用 CSS.paintWorklet.addModule('my-paint-worklet.js')
載入 CSS 油漆工作區檔案。在此檔案中,我們可以使用 registerPaint
函式註冊油漆工計畫類別:
class MyPainter {
paint(ctx, geometry, properties) {
// ...
}
}
registerPaint('myPainter', MyPainter);
在 paint()
回呼中,我們可以和從 <canvas>
瞭解的 CanvasRenderingContext2D
相同,使用 ctx
。如果您知道如何在 <canvas>
中繪圖,可以在顏料畫中繪圖!geometry
可讓我們知道畫布的寬度和高度。properties
我稍後會在這篇文章中說明。
以入門範例來說,我們開始編寫棋盤格繪畫工具,做為 <textarea>
的背景圖片。(我之所以使用文字區域,是因為這類文字預設為可調整大小):
<!-- 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);
如果您過去曾使用 <canvas>
,應該對這段程式碼十分熟悉。請參閱這裡的即時示範。
這裡使用常見的背景圖片的不同之處在於,每當使用者調整文字區域大小時,模式都會隨選重新繪製。這表示背景圖片的尺寸一律依照所需大小隨時調整,包括適用於高密度螢幕的補償。
很酷,但也很靜態。每次想採用相同模式但大小不同時,我們是否想編寫新的工作空間?答案是不會!
將 Worklet 參數化
幸好,繪製工作小程式可以存取其他 CSS 屬性,這也是 properties
額外參數的作用。為類別提供靜態的 inputProperties
屬性,即可訂閱任何 CSS 屬性 (包括自訂屬性) 的變更。值將透過 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);
現在我們就能針對各種不同類型的棋盤使用相同程式碼。不過更棒的是,現在可以進入開發人員工具,並填入值,直到找到正確的效果為止。
瀏覽器不支援油漆工
在本文撰寫期間,只有 Chrome 已實作顏料工作。雖然其他瀏覽器供應商皆有正向信號,但並沒有什麼進展。如要掌握最新資訊,請定期查看「Is Houdini Ready Yet?」。在此期間,請務必使用漸進式增強,讓程式碼在不支援繪製工作程式時也能持續運作。為確保能夠正常運作,您必須在兩個地方調整程式碼:CSS 和 JS。
您可以透過檢查 CSS
物件,在 JS 中偵測支援繪製工作的小程式:
js
if ('paintWorklet' in CSS) {
CSS.paintWorklet.addModule('mystuff.js');
}
CSS 端有兩種方法。您可以使用 @supports
:
@supports (background: paint(id)) {
/* ... */
}
更精簡的做法是使用 CSS 失效,並在其中存在不明函式時,忽略整個屬性宣告。如果您指定屬性兩次 (第一項沒有繪製 Worklet,然後使用油漆工作組),就可以採用漸進式的強化效果:
textarea {
background-image: linear-gradient(0, red, blue);
background-image: paint(myGradient, red, blue);
}
在「支援」繪畫工作程式的瀏覽器中,background-image
的第二個宣告會覆寫第一個宣告。在「不」支援繪製工作程式的瀏覽器中,第二個宣告無效並遭到捨棄,以便保留第一個宣告。
CSS 塗料 Polyfill
在許多用途中,您也可以使用 CSS 顏料 Polyfill,為新型瀏覽器新增 CSS 自訂繪製和 Paint Worklet 支援。
用途
油漆工件有許多用途,其中有些較明確。其中一個比較明顯的做法是使用顏料工作來縮減 DOM 大小。通常,元素僅供用來使用 CSS 建立裝飾。舉例來說,在 Material Design Lite 中,漣漪效果按鈕包含 2 個額外的 <span>
元素,用於實作漣漪效果。如果您有多個按鈕,可能會加入大量 DOM 元素,導致行動裝置的效能降低。如果您改用顏料工作程式實作漣漪效果,會最後獲得 0 個元素和一個繪製小程式。此外,您還能更輕鬆地自訂及參數化。
使用顏料工作的另一個好處是,在大多數情況下,使用顏料工作的解決方案是少量位元組的解決方案。當然,需要有所取捨:每當畫布大小或任何參數發生變更時,繪圖程式碼就會執行。因此,如果您的程式碼很複雜且花費較長時間,可能會導致卡頓。Chrome 正設法將繪製工作程式移出主執行緒,因此即使是長時間執行的繪製工作,也不會影響主執行緒的回應速度。
我認為最令人振奮的潛在客戶,就是透過繪製工作程式有效率地將各種 CSS 功能聚集到瀏覽器尚未具備的特色。其中一個例子就是將 Polyfill Conic 梯度,一直到 Chrome 以原生方式降落為止。另一個範例:在 CSS 會議中,我們認為現在可以設定多種邊框顏色。當這場會議繼續進行時,我的同事 Ian Kilpatrick 就使用顏料工作程式為這個新的 CSS 行為編寫 polyfill。
跳脫「盒子」的思維框架
大多數人在學習繪畫工事時,就會開始思考背景圖片和邊框圖片。繪製工作小程式的一個較直覺用途,就是使用 mask-image
,讓 DOM 元素具有任意形狀。例如菱形:
mask-image
會擷取元素大小的圖片。遮罩圖片透明的區域,元素會顯示為透明。遮罩圖片不透明的區域 (元素不透明)。
現已在 Chrome 中
套用小程式的 Chrome Canary 已有一段時間。在 Chrome 65 中,這項功能預設為啟用。快試試看畫圈的新可能性 看看你的成果吧!如需更多資訊,請查看 Vincent De Oliveira 的系列作品。