Summary
Houdini是CSS的發展方向之一,讓開發者擁有操作CSS引擎的能力,建立自定義的CSS。讓我們從自定義button樣式開始,快速上手Houdini。
Houdini是什麼?
為什麼需要它 - CSS的polyfill
相比保守的CSS,JS則可以更加自由地定義各種屬性和方法,實現各種抽象的邏輯。在近幾年的飛速發展中,開發者可以激進地使用最新的JS特性,並通過一系列ployfill解決瀏覽器的相容問題。CSS則與之相反,一直沒有開放CSS引擎的API。這使得開發者不得不十分謹慎地使用CSS,避免各種瀏覽器相容性問題。
為了加速CSS在社群的演進,Houdini作為一個新的W3C工作組,他們希望提供一套API,來讓開發者擁有操作CSS引擎的能力,進而建立自定義的CSS。Houdini工作組眾星雲集,Mozilla,Apple,Opera,Microsoft,HP,Intel和Google的工程師都參與其中。目前,Houdini還是一份草案,這裡展示了詳細內容。
Houdini的核心概念
從W3C的草案中,我們能夠發現Houdini計劃提供這幾種API/Class:Layout API,Painting API,Properties & Values API,Worklets,Typed OM,Box Tree API和Parser API。他們的相容性可以在ishoudini檢視。目前為止,Chrome (Canary)是相容性最好的瀏覽器。
本文以目前支援度最好的CSS Paint API為例,著重介紹兩個核心概念:Worklets和CSS Paint API。
Worklets
Worklets是一個在瀏覽器rendering pipeline執行指令碼的Class,它獨立於JS主執行緒。這聽起來和Web Workers很像,但它們的目標和區別在於
- Web Workers作為一個後臺執行的執行緒,完成一些長時間的工作而且不會阻塞主執行緒。它應該長時間存活,並消耗相對較多的CPU、記憶體。
- Worklets是個受渲染引擎控制的輕量化、短生命週期執行緒,開發者並不知道這個執行緒的具體情況,並且同一類Worklets可能有多個例項,並且直接註冊在Global scope。
可以認為Worklets是個抽象類,開發者需要實現它的子類,例如Paint Worklet。同時,僅定義Worklets是沒有任何效果的,需要把它註冊到Global Scope上。在下面的CSS Paint API我們能看到一個具體的例子。
CSS Paint API
CSS Paint API用來繪製一個CSS box的background,content和highlight。首先定義一個Paint Worklet,它是個JS Class。接著用registerPaint函式註冊到Global Scope。最後,我們在Demo中使用CSS.paintWorklet.addModule函式import這個JS Module。完成這3步後,就能在CSS中使用paint函式了,例如:background: paint('my-background')。
Paint Worklet用paint函式用來繪製圖案,它有4個引數
- ctx: 一個PaintRenderingContext2D例項,canvas的大部分功能都能夠使用
- size: 一個PaintSize例項,包含元素的width, height
- styleMap: 一個StylePropertyMapReadOnly例項,主要用於讀取DOM的style property
- args: paint函式的輸入引數,例如在CSS中宣告:background: paint('my-background', red),red就是一個輸入引數
inputProperties函式返回自定義的CSS Property Name,例如'--my-prop',不在此宣告的Property會被渲染引擎過濾,即無法在styleMap中讀取。
inputArguments函式返回自定義的CSS Property Value的格式,例如'<color>',預設時不做檢查,可被看成string。這裡是目前支援的格式。
class Button {
static get inputArguments() { return ['<color>'] }
static get inputProperties() { return ['--my-prop'] }
paint(ctx, size, styleMap, args) {
// paint function do drawing on the ctx, just like canvas
}
}
// this is the critical point
// registerPaint function is valid with CSS Paint API
registerPaint('button', Button)
複製程式碼
快速上手 - 自定義button
瞭解了Worklets和CSS Paint API後,我們就能開始自定義自己的button樣式。
定義Button Worklet
先定義Button Worklet。它定義了一個custom property: --my-bg-color,接著在paint函式中,呼叫drawBezierCurve函式畫了一條貝塞爾曲線。
class Button {
constructor() {
this.width = 0;
this.height = 0;
this.bgColor = "black";
}
static get inputProperties() {
return ["--my-bg-color"];
}
paint(ctx, size, styleMap) {
const { width, height } = size;
this.width = width;
this.height = height;
this.bgColor = styleMap
.get("--my-bg-color")
.toString()
.trim();
this.drawBezierCurve(ctx);
}
drawBezierCurve(ctx) {
ctx.fillStyle = this.bgColor;
ctx.beginPath();
ctx.moveTo(0, this.height);
ctx.lineTo(this.width / 4, this.height);
ctx.bezierCurveTo(
this.width / 3,
this.height,
this.width / 2,
this.height / 3 * 2,
this.width / 2,
this.height / 2
);
ctx.bezierCurveTo(
this.width / 2,
this.height / 3,
this.width / 3 * 2,
0,
this.width / 4 * 3,
0
);
ctx.lineTo(0, 0);
ctx.fill();
}
}
registerPaint("button", Button);
複製程式碼
See the Pen Button-Worklets by Shaw Che (@sche) on CodePen.
註冊這個PaintWorklet
第二步,在頁面中註冊這個PaintWorklet。
if (!CSS.paintWorklet) {
document.querySelector('#alert').classList.add('show-alert');
} else {
CSS.paintWorklet.addModule("https://codepen.io/sche/pen/KRadBG.js");
}
複製程式碼
<div id="alert" class="alert">
You need support for CSS Paint API to view this demo. Go to here to find a good web browser.
<a href="https://ishoudinireadyyet.com/">ishoudinireadyyet.com</a>
</div>
<input type="button" class="my-button" value="btn">
</input>
<input type="button" class="my-button" value="btn 2"></input>
<span class="my-button">
span btn
</span>
複製程式碼
.my-button {
--my-bg-color: lightblue;
width: 70px;
height: 20px;
border-radius: 10px;
color: black;
background-image: paint(button);
}
.alert {
display: none;
}
.show-alert {
display: block !important;
}
複製程式碼
See the Pen Houdini - Button by Shaw Che (@sche) on CodePen.
Reference
- https://drafts.css-houdini.org/
- https://ishoudinireadyyet.com/
- https://www.smashingmagazine.com/2016/03/houdini-maybe-the-most-exciting-development-in-css-youve-never-heard-of/
- https://zhuanlan.zhihu.com/p/35479957
- 封面圖片 - Photo by Denise Johnson on Unsplash