你是否曾想過 CSS 的工作量?變更單一屬性後,整個網站的版面配置就會突然變更。這有點像魔法。到目前為止,我們 (網頁開發人員社群) 只能見證和觀察這項奇蹟。如果想提出自己的魔法如果我們想成為魔術師呢?
進入 Houdini!
Houdini 特別工作小組由 Mozilla、Apple、Opera、Microsoft、HP、Intel 和 Google 的工程師組成,他們共同合作,向網路開發人員公開 CSS 引擎的特定部分。工作小組正在處理草稿集合,目標是讓草稿獲得 W3C 的認可,成為實際的網路標準。他們設定了幾個高層目標,並將這些目標轉換為規格草稿,進而產生一組支援的低階規格草稿。
當其他人談論「Houdini」時,這些草稿的集合通常代表著作。在本文撰寫時,草稿清單不完整,部分草稿只是預留位置。
規格
Worklet (spec)
Worklet 本身並沒有太大用處。這項概念的目的,是為了讓後續草稿能夠順利進行。如果您在閱讀「worklet」時想到 Web Workers,那麼您並沒有錯。它們在概念上有很多重疊之處。那麼在工作人員時 為什麼要推出新的東西呢?
Houdini 的目標是公開新的 API,讓網頁開發人員將自己的程式碼連結至 CSS 引擎和周圍系統。假設部分程式碼片段必須執行 Every.Single. frame 是非常實用的特性,其中有些是必須的。引述 Web Worker 規格:
也就是說,Houdini 的計畫無法使用網頁工作站。工作程式使用 ES2015 類別來定義方法的集合,也就是由工作程式類型預先定義的方法簽名。這些 cookie 體積輕巧,且壽命短暫。
CSS Paint API (規格)
根據預設,Chrome 65 會啟用 Paint API。請參閱詳細介紹。
合成器小程式
這裡所述的 API 已淘汰。我們已重新設計合成器工作區,並將其命名為「動畫工作區」。進一步瞭解 API 的目前版本。
雖然合成器工作區規格已移至 WICG,並將進行疊代,但這項規格是我最感興奮的規格。不過,CSS 引擎會將部分作業外包給電腦的顯示卡,但這取決於顯示卡和裝置的一般情況。
瀏覽器通常會使用 DOM 樹狀結構,並根據特定條件決定為某些分支和子樹狀結構建立專屬的圖層。這些子樹會將自己繪製到畫布上 (未來可能會使用繪製工作區)。最後,所有已繪製的個別圖層會堆疊並彼此堆疊,並遵循 z 索引、3D 轉換等,產生可在螢幕上顯示的最終圖片。這個程序稱為「合成」,由合成器執行。
合成程序的優點是,當頁面稍微捲動時,您不必讓所有元素重新繪製。您可以改為重複使用先前影格中的圖層,並以更新後的捲動位置重新執行合成器。這樣一來,處理速度就會加快。這有助於達到 60fps。
如其名稱所示,合成器工作區可讓您鉤掛至合成器,並影響已繪製的元素層位於其他層的頂端的方式。
如要進一步指定,您可以告訴瀏覽器,您想要鉤掛特定 DOM 節點的組合程序,並且可以要求存取特定屬性,例如捲動位置、transform
或 opacity
。這會強制將此元素置於其專屬圖層,並在每個影格呼叫程式碼。您可以透過操控圖層轉換並變更其屬性 (例如 opacity
) 來移動圖層,讓您以 60 fps 的速度執行精緻的操作。
以下是使用合成器工作區塊,針對視差捲動功能的完整實作方式。
// main.js
window.compositorWorklet.import('worklet.js')
.then(function() {
var animator = new CompositorAnimator('parallax');
animator.postMessage([
new CompositorProxy($('.scroller'), ['scrollTop']),
new CompositorProxy($('.parallax'), ['transform']),
]);
});
// worklet.js
registerCompositorAnimator('parallax', class {
tick(timestamp) {
var t = self.parallax.transform;
t.m42 = -0.1 * self.scroller.scrollTop;
self.parallax.transform = t;
}
onmessage(e) {
self.scroller = e.data[0];
self.parallax = e.data[1];
};
});
Robert Flack 已為合成器工作區編寫polyfill,歡迎您試試看,不過這會對效能造成較大的影響。
版面配置工作表 (spec)
我們已提出第一個實際規格草稿。實作並不容易。
再次強調,這個做法的規格幾乎是空的,但這個概念很有趣,那就是:編寫自己的版面配置!版面配置 Worklet 應可讓您執行 display: layout('myLayout')
並執行 JavaScript,在節點方塊中安排節點的子項。
當然,執行 CSS flex-box
版面的完整 JavaScript 實作項目會比執行等效的原生實作項目慢,但您很容易想像,在某些情況下,省略某些步驟就能提升效能。想像一個網站,其中只有方塊,例如 Windows 10 或磚牆式版面配置。不使用絕對和固定定位,也不使用 z-index
,元素也不會重疊,也不會有任何邊框或溢位。能夠略過所有重新版面配置的檢查,可能會帶來效能提升。
registerLayout('random-layout', class {
static get inputProperties() {
return [];
}
static get childrenInputProperties() {
return [];
}
layout(children, constraintSpace, styleMap) {
const width = constraintSpace.width;
const height = constraintSpace.height;
for (let child of children) {
const x = Math.random()*width;
const y = Math.random()*height;
const constraintSubSpace = new ConstraintSpace();
constraintSubSpace.width = width-x;
constraintSubSpace.height = height-y;
const childFragment = child.doLayout(constraintSubSpace);
childFragment.x = x;
childFragment.y = y;
}
return {
minContent: 0,
maxContent: 0,
width: width,
height: height,
fragments: [],
unPositionedChildren: [],
breakToken: null
};
}
});
類型 CSSOM (spec)
而 CSSOM (CSS 物件模型或階層式樣式試算表物件模型) 則解決了我們所有人剛剛遇到的問題,以及所學到的技巧。我將以一行 JavaScript 程式碼說明:
$('#someDiv').style.height = getRandomInt() + 'px';
我們會執行數學運算,將數字轉換為字串,再附加單位,讓瀏覽器剖析該字串,並將其轉換回 CSS 引擎的數字。如果您使用 JavaScript 操控轉換,情況會更糟。別再這樣了!CSS 即將開始輸入內容。
這個草稿是較成熟的草稿之一,且polyfill 也已在開發中。(免責聲明:使用 polyfill 顯然會增加更多運算開銷。重點是說明 API 有多方便。)
您將處理元素的 StylePropertyMap
,而非字串,其中每個 CSS 屬性都有其專屬的鍵和對應的值類型。width
等屬性具有 LengthValue
值類型。LengthValue
是所有 CSS 單位的字典,例如 em
、rem
、px
、percent
等。設定 height: calc(5px + 5%)
會產生 LengthValue{px: 5, percent: 5}
。box-sizing
等部分屬性僅接受特定關鍵字,因此具有 KeywordValue
值類型。接著,系統可以在執行階段檢查這些屬性的有效性。
<div style="width: 200px;" id="div1"></div>
<div style="width: 300px;" id="div2"></div>
<div id="div3"></div>
<div style="margin-left: calc(5em + 50%);" id="div4"></div>
var w1 = $('#div1').styleMap.get('width');
var w2 = $('#div2').styleMap.get('width');
$('#div3').styleMap.set('background-size',
[new SimpleLength(200, 'px'), w1.add(w2)])
$('#div4')).styleMap.get('margin-left')
// => {em: 5, percent: 50}
屬性和值
(spec)
您是否知道 CSS 自訂屬性 (或其非官方別名「CSS 變數」)? 這就是類型,到目前為止,變數只能包含字串值,並使用簡單的搜尋及取代方法。這份草稿不僅可讓您為變數指定類型,還可定義預設值,並使用 JavaScript API 影響繼承行為。從技術層面來說,這也能讓自訂屬性透過標準 CSS 轉場和動畫產生動畫效果,而我們也正在考慮這項功能。
["--scale-x", "--scale-y"].forEach(function(name) {
document.registerProperty({
name: name,
syntax: "<number>",
inherits: false,
initialValue: "1"
});
});
字型指標
字型指標顧名思義,當我以字串 X 和字型 Y 以大小 Z 算繪時,定界框 (或定界框) 為何?如果我使用Ruby 註解,會發生什麼情況?許多人提出這項要求,Houdini 終於實現這個願望。
等一下,好處可不只這些!
Houdini 的草稿清單中還有更多規格,但這些規格的未來發展相當不明確,也只不過是想法占位符。例如自訂溢位行為、CSS 語法擴充 API、原生捲動行為擴充功能,以及其他類似的擴充功能,這些功能可在網路平台上提供先前無法實現的功能。