瀏覽器即將推出 Cascade 圖層

烏娜克萊維茲
Una Kravets

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

以明確的方式疊加 CSS 可防止出現非預期的樣式覆寫,並促進更好的 CSS 架構。

CSS 專屬性和 Cascade

CSS 專用性是 CSS 決定要套用至元素的樣式的方式。您可使用不同的選取器決定任何樣式規則的明確性。舉例來說,元素較類別或屬性的具體性較低,因為類別或屬性的明確性就比 ID 來得低。這是學習 CSS 的其中一個元素。

民間公司會改用 BEM 等 CSS 命名慣例,以免在無意中覆寫特定設定。為所有項目取一個類別名稱,所有內容都在同一個具體的平面上進行。不過,您不一定能夠維護這類井然有序的樣式,尤其是在使用第三方程式碼和設計系統時。

以 BEM 圖像呈現課程資訊卡
透過 keepinguptodate.com 提供的 BEM 命名方式示例。

Cascade 圖層旨在解決這個問題。它們為 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 示範影片

整理匯入作業

另一種使用 @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 中的正規化、主題和字體排版檔案,在 layouts 中有 post 檔案,而在 components 中有 cardsfooter。匯入檔案時,圖層會使用圖層函式執行個體化。另一種方法是將圖層排在檔案頂端,並在匯入之前宣告這些圖層:

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

現在,@import 樣式的順序不會影響圖層順序,因為圖層名稱已在第一個例項中建立。這樣就少了一點需要擔心您仍可將匯入的檔案設為特定圖層,但系統已建立排序。

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

層和瀑布

我們先退一步,看看圖層在較大的層流關聯處:

Cascade 插圖

優先順序如下:

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

您可能會發現 @layer !important 樣式反轉。其優先順序較高,且較非圖層 (一般) 樣式更加明確。這是因為 !important 在階層中的運作方式:它會中斷樣式表中的一般階層式,並反轉一般層層級的特異性 (優先順序)。

巢狀層

圖層也可在其他圖層以巢狀結構嵌入。以下範例來自 Miriam Suzanne 的 Cascade LayersExplainer

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

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

  p { margin-bottom: 1em; }
}

在上述程式碼片段中,您可以使用 . 作為 framework 內巢狀結構的 default 圖層的符號,以存取 framework.default。您也可以用更簡潔的格式來撰寫:

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

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

  • 預設
  • framework.default
  • framework 個未疊加的項目
  • 無層次

注意事項

如果正確使用 Cascade 圖層,這是很不錯的做法,但也會造成混淆,並產生意外的結果。使用階層式圖層時,請注意下列事項:

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

Cascade 層無法解析範圍。如果有 CSS 檔案含有 @layer,以 card.css 為例,並想為資訊卡內所有連結設定樣式,請勿撰寫下列樣式:

a {
  …
}

這會導致檔案中的所有 a 標記都會獲得此覆寫。仍請務必妥善設定樣式:

.card a {
  …
}

規則 2:串聯圖層排序在非層式 CSS 後方

請特別注意,圖層的 CSS 檔案「不會」覆寫非圖層的 CSS。這是我們刻意做出的決定,是要以更合理的方式導入現有程式碼集。例如,使用 reset.css 檔案是一個很好的起點,以及 Cascade 圖層的用途。

規則 3:!important 反轉串聯專屬性

儘管圖層樣式的具體性較低,但大致上沒有圖層的樣式,使用 !important 則會反轉。在圖層中,具有 !important 規則的宣告比未層樣式的宣告「更嚴格」。

在這種情況下,!important 樣式會反轉其特異性。上圖顯示這項資訊,參考:author @layers,比作者一般標準低,但優先順序比作者 @layer !important 低。

如有多個圖層,含有 !important 的第一個圖層優先於 !important,且是內容最明確的樣式。

規則 4:瞭解插入點

由於圖層順序是依每個圖層名稱出現在程式碼首次出現的時間所建立,因此如果您在匯入並設定 layer()’ 後加入 @layer 宣告,或是在不同的 @layer 陳述式之後加入宣告,系統就會忽略這個順序。與 CSS 不同,網頁上最底部的樣式規則套用於階層式圖層時,會在第一個例項上建立順序。

可能在清單、圖層區塊或匯入作業中。如果在含有 layer() 的匯入清單後方放置 @layer,則不會執行任何動作。放在檔案頂端會設定圖層順序,並有助於您清楚看見架構中的各個圖層。

規則 5:留意具體性

使用 Cascade 圖層時,如果較不明確的選取器 (例如 .link) 位於更具體的圖層,則較不明確的選取器 (例如 a) 將覆寫該選取器。請把握以下幾項重點:

如果指定 @layer utilities, componentslayer(components) 中的 a 會覆寫 layer(utilities) 中的 .pink。雖然是刻意使用的 API,但如果您在不知情的情況下未預期使用 API,可能會感到困惑與困擾。

因此,如要編寫公用程式類別,請一律將這些類別納入順序較高的層,而非要覆寫的元件。您可能會認為「我剛新增這個 .pink 類別來變更顏色,因此無法套用。」

進一步瞭解階層層

您也可以查看下列資源,進一步瞭解階層式圖層: