本文將介紹自 Chrome 85 版起,開始在開發人員工具中的 CSS-in-JS 支援,以及 CSS-in-JS 代表的意義,以及這項工具與開發人員工具長久以來支援的一般 CSS 有何不同。
什麼是 CSS-in-JS?
CSS-in-JS 的定義不夠明確。大致上來說,這是使用 JavaScript 管理 CSS 程式碼的方法。舉例來說,可能表示 CSS 內容是以 JavaScript 定義,且應用程式即時產生最終 CSS 輸出內容。
在開發人員工具中,CSS-in-JS 代表使用 CSSOM API 將 CSS 內容插入網頁中。一般的 CSS 是使用 <style>
或 <link>
元素插入,且具有靜態來源 (例如 DOM 節點或網路資源)。相較之下,CSS-in-JS 通常沒有靜態來源。這裡的特殊案例是,您可以使用 CSSOM API 更新 <style>
元素的內容,導致來源與實際的 CSS 樣式表不同步。
如果您使用任何 CSS-in-JS 程式庫 (例如 styled-component、Emotion、JSS),程式庫可能會根據開發模式和瀏覽器,在背景使用 CSSOM API 插入樣式。
讓我們來看看一些範例,瞭解如何使用 CSSOM API 插入樣式表,做法和 CSS-in-JS 程式庫的運作方式類似。
// Insert new rule to an existing CSS stylesheet
const element = document.querySelector('style');
const stylesheet = element.sheet;
stylesheet.replaceSync('.some { color: blue; }');
stylesheet.insertRule('.some { color: green; }');
除此之外,您也可以建立全新的樣式表:
// Create a completely new stylesheet
const stylesheet = new CSSStyleSheet();
stylesheet.replaceSync('.some { color: blue; }');
stylesheet.insertRule('.some { color: green; }');
// Apply constructed stylesheet to the document
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
開發人員工具中的 CSS 支援
在開發人員工具中,處理 CSS 最常用的功能是「樣式」窗格。在「樣式」窗格中,您可以查看特定元素所套用的規則,以及編輯規則並即時檢視網頁上的變更。
去年,我們對於使用 CSSOM API 修改 CSS 規則的支援範圍有限:您只能查看已套用的規則,但無法編輯。我們去年的主要目標,是讓使用者利用「樣式」窗格,編輯 CSS 內部的 CSS 規則。有時我們也會將 CSS 內樣式稱為「建構式」,指出這些樣式是使用 Web API 所建構。
接下來詳細說明開發人員工具中的樣式編輯功能。
開發人員工具中的樣式編輯機制
當您在開發人員工具中選取元素時,系統會顯示「Styles」窗格。Styles 窗格會發出名為 CSS.getMatchedStylesForNode 的 CDP 指令,以便取得套用至該元素的 CSS 規則。CDP 是 Chrome 開發人員工具通訊協定的一個 API,這個 API 可讓 DevTools 前端取得已檢查頁面的其他相關資訊。
叫用 CSS.getMatchedStylesForNode
時,會識別文件中的所有樣式表,並透過瀏覽器的 CSS 剖析器進行剖析。接著會建立索引,將每個 CSS 規則與樣式表來源中的位置建立關聯。
您可能會好奇,為何還需要再次剖析 CSS?這會導致問題是,瀏覽器本身就不受 CSS 規則的來源位置影響,因此不會儲存這些規則。不過,開發人員工具需要來源位置才能支援 CSS 編輯功能。我們不希望一般 Chrome 使用者支付效能降低,但我們希望開發人員工具使用者能存取來源位置。這種重新剖析方法以最少的缺點解決這兩種用途。
接著,CSS.getMatchedStylesForNode
實作會要求瀏覽器的樣式引擎提供與指定元素相符的 CSS 規則。最後,這個方法會將樣式引擎傳回的規則與原始碼建立關聯,並提供 CSS 規則的結構化回應,讓開發人員工具瞭解規則的哪個部分是選取器或屬性。可讓開發人員工具獨立編輯選取器和屬性。
接著來看看編輯功能別忘了,CSS.getMatchedStylesForNode
會傳回每項規則的來源位置。這對編輯來說非常重要。變更規則時,開發人員工具會發出另一個 CDP 指令,用於實際更新頁面。這個指令包含待更新規則片段的原始位置,以及片段需要更新的新文字。
在後端處理編輯呼叫時,開發人員工具會更新目標樣式表。也會更新負責維護的樣式表來源副本,並更新更新規則的來源位置。為了回應編輯呼叫,開發人員工具前端會傳回剛更新的文字片段的更新位置。
這就說明瞭為何在 DevTools 中編輯 CSS-in-JS 的功能無法立即運作:CSS-in-JS 未實際儲存任何來源,以及 CSS 規則位於瀏覽器的記憶體內 CSSOM 資料結構中。
我們如何新增 CSS-in-JS 支援
因此,為了支援 CSS-in-JS 規則的編輯功能,我們決定最好的解決方法,是為建構的樣式表建立來源,並使用上述現有機制進行編輯。
第一步是建構來源文字。瀏覽器的樣式引擎會將 CSS 規則儲存在 CSSStyleSheet
類別中。該類別就是前面提到的,您可以透過 JavaScript 建立的執行個體。建構來源文字的程式碼如下:
String InspectorStyleSheet::CollectStyleSheetRules() {
StringBuilder builder;
for (unsigned i = 0; i < page_style_sheet_->length(); i++) {
builder.Append(page_style_sheet_->item(i)->cssText());
builder.Append('\n');
}
return builder.ToString();
}
它會疊代處理 CSSStyleSheet 例項中的規則,並從中建構單一字串。建立 InspectorStyleSheet 類別的例項時,就會叫用這個方法。InspectorStyleSheet 類別會包裝 CSSStyleSheet 執行個體,並擷取開發人員工具所需的其他中繼資料:
void InspectorStyleSheet::UpdateText() {
String text;
bool success = InspectorStyleSheetText(&text);
if (!success)
success = InlineStyleSheetText(&text);
if (!success)
success = ResourceStyleSheetText(&text);
if (!success)
success = CSSOMStyleSheetText(&text);
if (success)
InnerSetText(text, false);
}
在這個程式碼片段中,我們會看見 CSSOMStyleSheetText
會在內部呼叫 CollectStyleSheetRules
。如果樣式表不是內嵌樣式或資源樣式表,系統會叫用 CSSOMStyleSheetText
。基本上,這兩個程式碼片段已允許對使用 new CSSStyleSheet()
建構函式建立的樣式表進行基本編輯。
特殊情況是指與已使用 CSSOM API 變更的 <style>
標記相關聯的樣式表。在此情況下,樣式表包含來源中沒有的來源文字和額外規則。為處理這種情況,我們引進了可將這些額外規則合併至來源文字的方法。由於 CSS 規則可以插入原始來源文字的中間,所以順序非常重要。舉例來說,假設原始 <style>
元素含有下列文字:
/* comment */
.rule1 {}
.rule3 {}
然後,頁面使用 JS API 插入了部分新規則,並產生下列規則順序:.rule0、.rule1、.rule2、.rule3、.rule4。合併作業後產生的來源文字應如下所示:
.rule0 {}
/* comment */
.rule1 {}
.rule2 {}
.rule3 {}
.rule4 {}
由於規則的來源文字位置必須精確,所以編輯原始註解和縮排相當重要。
CSS-in-JS 樣式表的另一個特點,是網頁可隨時變更。如果實際的 CSSOM 規則與文字版本不同步,便無法進行編輯。為此,我們導入了一種稱作「探測器」,可讓瀏覽器在樣式表變更時通知開發人員工具的後端部分。接著,系統會在下次呼叫 CSS.getMatchedStylesForNode 時,同步處理修改過的樣式表。
完成上述所有設定後,CSS 內文字編輯功能即可正常運作,但我們還是想改善使用者介面,以表明是否已建構樣式表。我們已在 CDP 的 CSS.CSSStyleSheetHeader 中新增 isConstructed
屬性,以供前端用來正確顯示 CSS 規則的來源:
結論
為回顧一下我們的經驗,我們探討了開發人員工具不支援的 CSS-in-JS 相關用途,並逐步探討開發這些用途的解決方案。這個實作過程有趣的部分在於,我們能夠讓 CSSOM CSS 規則具有一般來源文字,充分運用現有功能,而不必在開發人員工具中重新設定樣式。
如需更多背景資訊,請參閱設計提案或列有所有相關修補程式的 Chromium 追蹤錯誤。
下載預覽頻道
建議您使用 Chrome Canary、開發人員版或 Beta 版做為預設開發瀏覽器。這些預覽管道可讓您使用最新的開發人員工具、測試最先進的網路平台 API,以及在使用者操作之前在網站上找出問題!
與 Chrome 開發人員工具團隊聯絡
使用下列選項,在文章中討論新功能和異動,或與開發人員工具相關的任何其他內容。
- 透過 crbug.com 提供建議或意見。
- 如要回報開發人員工具問題,請在開發人員工具中依序點選「更多選項」 >「說明」 >「回報開發人員工具的問題」。
- 在 @ChromeDevTools 張貼推文。
- 歡迎前往開發人員工具的 YouTube 影片或開發人員工具的 YouTube 影片提供新功能留言。