瀏覽器即將推出 Cascade 圖層

層級串連 (@layer CSS 規則) 即將在 Chromium 99、Firefox 97 和 Safari 15.4 Beta 中推出。可讓您更明確地控制 CSS 檔案,避免樣式專屬性衝突。這對於大型程式碼集、設計系統,以及在應用程式中管理第三方樣式時特別實用。

以清楚的方式分層 CSS 可避免意外的樣式覆寫,並促進更優質的 CSS 架構。

CSS 特殊性和層疊

CSS 特異性是 CSS 決定要將哪些樣式套用至哪些元素的方式。您可以使用不同的選取器,決定任何樣式規則的特定性。舉例來說,元素的特定性低於類別或屬性,而類別或屬性的特定性又低於 ID。這是學習 CSS 的基礎知識。

為了避免不小心覆寫特定性,許多人會採用 BEM 等 CSS 命名慣例。為所有內容提供單一類別名稱,即可將所有內容置於相同的特定性平面。不過,您不一定能維持這種有條理的樣式,尤其是在使用第三方程式碼和設計系統時。

含有類別的卡片 BEM 視覺效果
BEM 命名方式的示例,摘自 keepinguptodate.com

而分層式層級就是為瞭解決這個問題。這些屬性會在 CSS 階層中引入新的。在使用分層樣式時,的優先順序一律高於選取器的特定性。

舉例來說,選取器 .post a.link 的特定性高於 .card a。如果嘗試在文章中的資訊卡中設定連結樣式,系統會套用更精確的選取器。

使用 @layer 時,您可以更明確地指定各樣式的特定性,並確保資訊卡連結的樣式會覆寫貼文連結的樣式,即使所有 CSS 都位於同一平面,特定性在數值上可能會較低。這是因為階層優先順序。分層樣式會建立新的層疊「平面」。

專案示範中分離 UI 的插圖

@layer 應用實例

示範顯示進口連結的顏色
查看 Codepen 上的示範

這個範例使用 @layer 展示串連層的強大功能。畫面上會顯示多個連結:有些連結沒有套用任何額外的類別名稱、有些連結套用 .link 類別,有些連結套用 .pink 類別。接著,CSS 會新增三個圖層:basetypographyutilities,如下所示:

@layer base {
  a {
    font-weight: 800;
    color: red; /* ignored */
  }

  .link {
    color: blue; /* ignored */
  }
}

@layer typography {
  a {
    color: green; /* styles *all* links */
  }
}

@layer utilities {
  .pink {
    color: hotpink;  /* styles *all* .pink's */
  }
}

最後,所有連結都會顯示為綠色或粉紅色。這是因為:雖然 .link 的選取器層級特定性高於 a,但 a 的顏色樣式在優先順序較高的 @layer 中。當綠色規則位於藍色規則後面的圖層時,a { color: green } 會覆寫 .link { color: blue }

層級優先順序優於元素明確性。

整理圖層

您可以直接在頁面上整理圖層,如上圖所示,也可以在檔案頂端整理圖層。

圖層順序是由每個圖層名稱在程式碼中首次出現時建立。

也就是說,如果您在檔案頂端新增下列內容,連結就會全部顯示紅色,而類別為 .link 的連結則會顯示藍色:

@layer utilities, typography, base;

這是因為現在的圖層順序已反轉,先顯示公用程式,再顯示基礎圖層。因此,base 圖層中的樣式規則一律會比字體排版圖層中的樣式規則更具特異性。這些連結不再是綠色,而是紅色或藍色。

Codepen 專案的螢幕截圖
查看 Codepen 上的示範

整理匯入項目

另一種使用 @layer 的方式是匯入檔案。您可以在匯入樣式時直接執行此操作,方法是使用 layer() 函式,如以下範例所示:

/* Base */
@import '../styles/base/normalize.css' layer(base); /* normalize or rest file */
@import '../styles/base/base.css' layer(base); /* body and base styles */
@import '../styles/base/theme.css' layer(theme); /* theme variables */
@import '../styles/base/typography.css' layer(theme); /* theme typography */
@import '../styles/base/utilities.css' layer(utilities); /* base utilities */

/* Layouts */
@import '../styles/components/post.css' layer(layouts); /* post layout */

/* Components */
@import '../styles/components/cards.css' layer(components); /* imports card */
@import '../styles/components/footer.css' layer(components); /* footer component */

上述程式碼片段有三個層級:baselayoutscomponentsbase 中的 normalize、主題和字體排版檔案,layouts 中的 post 檔案,以及 components 中的 cardsfooter。匯入檔案時,系統會使用圖層函式將圖層例項化。另一種做法是在檔案頂端整理圖層,並在任何匯入作業之前宣告圖層:

@layer base,
       theme,
       layouts,
       components,
       utilities;

如今,您 @import 樣式的順序對圖層順序沒有影響,因為圖層順序已在圖層名稱的首個例項中建立。這樣就少了一項讓人擔心的事。您還是可以將匯入的檔案設為特定圖層,但順序已確定。

Codepen 專案的螢幕截圖
探索 Codepen 上的專案

層級和階層

讓我們回顧一下,看看層級在哪些地方與更廣泛的層級相關:

階層插圖

優先順序如下:

  • 使用者代理程式正常 (最低優先順序)
  • 本機使用者 @layer
  • 本機使用者正常
  • 作者 @layers
  • 作者正常
  • 作者 !important
  • 作者 @layer !important
  • 本機使用者 !important
  • 使用者代理程式 !important** (最高優先順序)

您可能會發現 @layer !important 樣式已反轉。相較於非分層 (一般) 樣式,它們具有較高的優先順序,這是因為 !important 在層疊中的作用方式:它會中斷樣式表中的正常層疊,並反轉正常的層級層級特異性 (優先順序)。

巢狀圖層

您也可以在其他圖層中嵌套圖層。以下範例取自 Miriam Suzanne 的層級式疊代說明

@layer default {
  p { max-width: 70ch; }
}

@layer framework {
  @layer default {
    p { margin-block: 0.75em; }
  }

  p { margin-bottom: 1em; }
}

在上述程式碼片段中,您可以使用 . 存取 framework.default,並將 . 做為 default 層在 framework 中巢狀結構的標記。您也可以使用更簡略的格式編寫:

@layer framework.default {
  p { margin-block: 0.75em }
}

產生的圖層和圖層順序如下:

  • 預設
  • framework.default
  • framework 未分層
  • 未分層

注意事項

只要正確使用,階層式層級就能發揮極大效用,但也可能造成混淆,並產生非預期的結果。使用級聯層時,請注意下列事項:

規則 1:請勿使用 @layer 進行範圍設定

分層設定無法解決範圍設定問題。如果您有含 @layer 的 CSS 檔案 (例如 card.css),且想要為資訊卡中的所有連結套用樣式,請勿編寫以下樣式:

a {
  
}

這麼做會導致檔案中的所有 a 標記都收到這個覆寫值。不過,您還是需要正確設定範圍樣式:

.card a {
  
}

規則 2:分層圖層的排序會排在非分層 CSS 後方

請注意,分層 CSS 檔案「不會」覆寫非分層 CSS。我們刻意做出這個決定,讓您能以更合理的方式引入圖層,以便與現有的程式碼庫搭配使用。例如,使用 reset.css 檔案是建立層疊式圖層的良好起點和用途。

規則 3:!important 會反轉層疊的特定性

雖然一般來說,分層樣式不如非分層樣式具體,但使用 !important 可反轉這個情況。在圖層中,使用 !important 規則的宣告比未分層樣式更具特徵

在這種情況下,!important 樣式會反轉其特定性。請參考下方圖表:author @layer 的優先順序低於 author normal,而 author normal 的優先順序低於 author !important,而 author !important 的優先順序低於 author @layer !important。

如果您有多個圖層,第一個含有 !important 的圖層會優先採用 !important,並成為最具體的樣式。

規則 4:瞭解注入點

由於每個圖層名稱在程式碼中首次出現時就會建立圖層順序,因此如果您在匯入及設定 layer() 之後,或在其他 @layer 陳述式之後放置 @layer 宣告,系統會忽略該宣告。與 CSS 不同的是,CSS 會將網頁最底部的樣式規則套用至層疊層,而此處則會在初始例項中建立順序。

這可以是清單、圖層區塊或匯入內容。如果在含有 layer() 的匯入清單後方加入 @layer,系統不會執行任何動作。將其放在檔案頂端,即可設定圖層順序,並清楚查看架構中的圖層。

規則 #5:留意精確度

在階層層級中,如果較不精確的選取器 (例如 a) 位於較精確的層級,就會覆寫較精確的選取器 (例如 .link)。請把握以下幾項重點:

如果指定了 @layer utilities, componentslayer(components) 中的 a 會覆寫 layer(utilities) 中的 .pink。雖然這是 API 的預設行為,但如果您不預期會發生這種情況,可能會感到困惑和沮喪。

因此,如果您要編寫公用類別,請一律將其納入比要覆寫的元件更高階的層級。您可能會想:「我剛剛新增了這個 .pink 類別來變更顏色,但並未套用」。

進一步瞭解串連層

如要進一步瞭解串連層,請參考下列資源: