要在現有 CSS 中導入串接圖層,請先決定舊規則應放在哪裡。未分層的普通規則優先於所有具名圖層,因此只有在將相互競爭的舊規則移至優先順序較低的圖層後,新的分層覆寫規則才會生效。

本指南適用於在 Mac 上編輯自製網頁,並在桌面瀏覽器中檢查頁面的人。具體任務是將現有樣式表置於新的元件樣式之下,同時保留清楚易懂的遷移路徑。範例使用本機檔案、虛構標籤和簡單的 CSS 結構。

為什麼新的分層樣式會輸給現有規則?

在作者樣式表中相互競爭的普通宣告中,未分層的 CSS 優先於任何明確圖層中的 CSS。更具體的選擇器或圖層內較晚的位置都無法突破這個界線。CSS 規格以未分層規則覆寫更具體的分層規則為例,說明了這種行為。CSS 串接與繼承第 5 級。

請看以下 CSS 片段,它以類別為 tile 的元素為目標:

.tile {
  background-color: #b8bdc5;
}

@layer components {
  .tile {
    background-color: #246a73;
  }
}

背景仍會是灰色。將圖層命名為 overrides、把區塊移到檔案更後面,或提高選擇器的特異性,都不會改變未分層普通規則的優先順序。圖層名稱沒有內建含義;其宣告順序決定彼此的關係。MDN:串接圖層。

下表假設相互競爭的樣式表宣告位於相同的作者來源和情境,且沒有行內樣式、動畫或轉場影響該屬性。每列依優先順序由低至高排列。

宣告類型 優先順序由低至高
普通 最先宣告的圖層 → 後續宣告的圖層 → 未分層規則
!important 未分層規則 → 後續宣告的圖層 → 最先宣告的圖層

圖層優先順序會先於選擇器特異性判定。在勝出的圖層中,特異性仍然重要;如果宣告其他條件相同,來源順序可以決定勝負。重要宣告的優先順序反轉,表示遷移時必須分別考量普通規則和重要規則。MDN:串接圖層。

應選擇哪個遷移界線?

先找出一個新 CSS 需要控制的元素和屬性。檢查目前勝出的宣告、找出其樣式表,並判斷你是否能修改該檔案或調整頁面的載入方式。這樣就能找出最小且實用的遷移界線。

你的情況 實際做法 結果
現有 CSS 必須維持優先順序 保持未分層,並新增優先順序較低的分層預設值 新圖層會在沒有較強規則相互競爭時提供值
你可以編輯現有 CSS 將符合條件的舊規則放進 @layer legacy 後續圖層可以覆寫普通舊規則
你可以變更樣式表的進入點 使用 layer(legacy) 匯入現有檔案 匯入的樣式表會加入該圖層,無需改寫選擇器
你無法變更相互競爭的舊 CSS 或其載入方式 暫時讓必要的覆寫規則保持未分層 你仍須處理特異性和其他串接因素

這些做法依循 CSS 文件所述的三種圖層機制:用陳述式宣告圖層名稱、用區塊將規則指派給圖層,以及透過分層匯入將匯入的樣式表指派給圖層。單獨的陳述式不會移動現有規則。CSS 串接與繼承第 5 級:宣告串接圖層。

對於小型樣式表,將一般規則包在圖層中可能很方便。對於現有外部檔案,分層匯入能建立清楚的界線。不要將現有的 @import 規則放進 @layer 區塊:匯入屬於頂層規則,且有位置限制。MDN:@import。

以下建議的遷移方式會將舊檔案匯入具名圖層。這會改變它相對於其他樣式表的優先順序,因此在將相同變更套用到範例頁面以外之前,請先檢查其他已載入的 CSS。

如何在 Mac 上建立完整的本機範例?

建立一個資料夾,放入以下三個純文字檔案。使用程式碼編輯器,並保留 .html 和 .css 副檔名。這些檔案不需要套件、指令碼、字型或下載的資源。檔名是本機範例資源。

將以下完整文件存成 sample.html:

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Layer sample</title>
  <link rel="stylesheet" href="styles.css">
</head>
<body>
  <main id="sample">
    <h1>Shape sample</h1>
    <p>Tile A</p>
    <div class="tile" aria-label="Sample shape"></div>
  </main>
</body>
</html>

此文件只連結到 styles.css。HTML 使用 rel="stylesheet" 和 href,將外部樣式表與頁面建立關聯。目前的 HTML 標準並未為 link 元素定義 layer 屬性;請透過 CSS 將資源指派給圖層。HTML 標準:link 元素。

將以下完整樣式表存成 legacy.css。它代表選擇器保持不變的現有規則:

body {
  margin: 2rem;
  font-family: system-ui, sans-serif;
  color: #26313a;
  background-color: #f4f5f7;
}

#sample .tile {
  width: 6rem;
  height: 6rem;
  background-color: #b8bdc5;
  border-radius: 0;
}

將以下完整進入樣式表存成 styles.css:

@layer legacy, components;
@import url("legacy.css") layer(legacy);

@layer components {
  .tile {
    background-color: #246a73;
    border-radius: 50%;
  }
}

在目前版本的桌面 Safari 或 Firefox 中開啟 sample.html。預期結果是在「Tile A」標籤下方出現一個青綠色圓形。舊圖層提供尺寸,後續的元件圖層則提供背景和圓角形狀。由於這些宣告分屬不同圖層,單一類別選擇器會勝過舊圖層中的 ID 選擇器。MDN:@layer。

進入檔案會先設定圖層順序,接著在區塊之前保留匯入,最後加入元件規則。這符合文件所述的匯入語法和位置規則。圖層陳述式可以放在匯入之前;圖層區塊則不行。MDN:@import。

如何變更現有頁面?

採用這種配置時,請將頁面直接引用的樣式表替換為新的進入樣式表。如果頁面仍直接載入 legacy.css,同時又將它匯入圖層,直接載入的未分層宣告可能會使遷移失效。

用範例來預測失敗情況:另外新增一個直接連結到 legacy.css 的樣式表,其普通宣告可能會讓灰色方塊重新出現。移除該直接載入後,舊規則就會留在預定的圖層中。這項預測符合規格中普通優先順序將未分層規則排在明確圖層之後的規定。CSS 串接與繼承模組第 5 級:圖層順序。

此範例請將三個檔案放在一起。調整到實際做法時,請保留現有的資源條件,例如媒體限制,並確認每個引用的樣式表都已載入,再判斷是否存在串接衝突。

如何在 macOS 的 Firefox 中驗證遷移?

按下 Command–Option–I 開啟 Firefox 開發者工具箱,並選取 Inspector。在文件樹中選取範例圖形,然後查看 Rules 檢視畫面。Mozilla 說明了 Mac 工具箱快捷鍵,以及 Inspector 的 CSS 檢查功能。所有鍵盤快捷鍵、檢查與編輯 CSS。

一次檢查範例中的一個屬性:

  1. 找出 background-color。元件宣告應勝過舊的灰色值。
  2. 找出 border-radius。元件值應使圖形呈現圓形。
  3. 檢查 width 和 height。這兩者的值應仍來自舊檔案。
  4. 暫時停用元件的背景宣告。圖形保持圓角的同時,應會顯示舊的灰色背景。

Firefox 會將被覆寫的宣告劃掉,並提供核取方塊供你暫時停用宣告。它也會將規則連結到來源檔案。請利用這些控制項找出相互競爭的宣告,不要把每個意外結果都當成選擇器問題。Mozilla:檢查與編輯 CSS。

對於實際頁面,請針對你變更過的狀態重複檢查:較窄的視窗、相關媒體條件,以及不同的元件變體。請將永久變更儲存在來源檔案中並重新載入;暫時的檢查變更適合用於診斷。

遷移期間可能有哪些意外變化?

重要宣告會反轉預期順序

使用 @layer legacy, components 時,legacy 中的重要宣告會勝過 components 中相互競爭的重要宣告。因此,將重要舊規則移入較早的圖層,可能會讓它們更難覆寫。在相同作者來源和情境中,所有分層的重要樣式表宣告也都會優先於相互競爭的未分層重要樣式表宣告。MDN:@layer。

移動檔案之前,請搜尋其中的 !important,並檢查每個相關衝突。若兩個宣告都由你控制,請判斷導入圖層後是否仍需要重要性。不要在每個新元件規則都加上重要性:這會改變你使用的優先順序系統。

行內樣式需要另外留意。普通行內樣式優先於普通作者樣式表規則,重要行內樣式也優先於其他作者的重要宣告。將樣式表移入圖層不會移動元素的 style 屬性。MDN:CSS 串接簡介。

較晚的陳述式無法重新排列現有圖層

圖層的順序取決於它首次宣告的位置。重新開啟具名圖層只會新增規則,不會移動該圖層。請在頁面首次建立這些圖層之前設定預期順序,包含透過匯入樣式表建立圖層的情況。CSS 串接與繼承模組第 5 級。

逐步遷移時,請讓初始順序保持簡短明確。移動一組完整相關的規則、檢查勝出的宣告,再繼續下一步。只移動一條規則,卻留下相互競爭的未分層副本,通常會保留你原本打算消除的優先順序界線。

在 Mac 上需要留意哪些瀏覽器支援限制?

MDN 標示 @layer 自 2022 年 3 月起已廣泛受到各瀏覽器支援。WebKit 記錄 Safari 15.4 加入了串接圖層支援。這些日期描述功能的可用時間,並不表示每台 Mac 都已安裝支援此功能的瀏覽器。請確認頁面實際需要支援的版本。MDN:@layer、WebKit:Safari 15.4 的 WebKit 新功能。

不認得圖層區塊的瀏覽器不會將其中的樣式當成一般未分層規則套用。依照 CSS 解析規則,不受支援的語法會被捨棄。因此,將所有必要 CSS 都包在圖層中,不能作為舊版瀏覽器的備援方案。MDN:CSS 錯誤處理。

如果仍須支援這些瀏覽器,請為該支援路徑保留刻意維持未分層的樣式表,並透過選擇器和來源順序解決衝突。在支援圖層的瀏覽器中,避免同時載入未分層的重複版本:這會改變你剛設計好的串接結果。

從最小規模的遷移開始,讓新元件能控制預定的屬性。設定圖層順序、將相互競爭的舊規則指派給圖層、移除重複的未分層載入方式,並檢查最後勝出的宣告。依照這個順序操作,就能在遷移更多 CSS 前清楚看出每次優先順序變化。

來源