網站導覽

基本概念

串接層

以 utility 覆寫共用元件,並找出規則衝突、未分層 CSS 與重要性造成的影響。

本頁目錄

#概述

局部調整不必提高選擇器權重。將共用元件規則放在 components 層,再由個別實例的 utility 覆寫需要改變的屬性。

較後的層決定局部內距

在這些一般宣告之間,utilities 的優先順序高於 components。HTML 中的 class 順序不會改變結果。

文字說明
  1. 建立順序. 預設樣式集依序宣告 theme、base、defaults、components、utilities。
  2. 比較宣告. 原生 collection-card 元件提供 1.5rem 內距。同一元素上的 p-sm 則在較後的 utilities 層提供 0.75rem 內距。
  3. 觀察結果. 在這些一般宣告之間,utility 會生效。根字級為 16px 時,計算後的內距是 12px。

#局部覆寫元件樣式

CSS 串接層會先決定各組宣告的順序,再比較選擇器權重。將可重用的元件樣式放在 components 層;當某個實例需要不同的值時,再加上 utility:

共用元件,局部調整

@layer components {  .collection-card {    padding: 1.5rem;    border: 1px solid var(--color-line-divider);    border-radius: var(--radius-lg);    background-color: var(--color-surface-raised);  }}
產生的 CSS
@layer components {  .collection-card {    border: 1px solid var(--color-line-divider);    border-radius: var(--radius-lg);    background-color: var(--color-surface-raised);    padding: 1.5rem;  }}@layer theme {  :root,  :host {    --color-zinc-40: oklch(68.6% .0028 265);    --color-zinc-60: oklch(48.6% .003 265);    --color-zinc-90: oklch(24.6% .0022 265)  }  :root,  :host {    --color-surface-raised: light-dark(var(--color-white), var(--color-zinc-90));    --color-line-divider: light-dark(oklch(0% 0 none / .12), oklch(100% 0 none / .12));    --color-text-muted: light-dark(var(--color-zinc-60), var(--color-zinc-40))  }  :root,  :host {    --color-white: oklch(100% 0 none)  }  :root,  :host {    --font-weight-regular: 400;    --font-size-sm: .875rem;    --font-size-lg: 1.125rem;    --text-sm: var(--font-size-sm);    --text-sm--line-height: 1.5;    --text-sm--letter-spacing: 0;    --text-lg: var(--font-size-lg);    --text-lg--line-height: 1.5;    --text-lg--letter-spacing: 0;    --radius-lg: .5rem;    --spacing-xs: .5rem;    --spacing-sm: .75rem;    --spacing-lg: 1.5rem  }}@layer utilities {  .text-lg {    font-size: var(--text-lg);    line-height: var(--text-lg--line-height, normal);    letter-spacing: var(--text-lg--letter-spacing, normal)  }  .text-sm {    font-size: var(--text-sm);    line-height: var(--text-sm--line-height, normal);    letter-spacing: var(--text-sm--letter-spacing, normal)  }  .grid-cols\(1\) {    display: grid;    grid-template-columns: repeat(1, minmax(0, 1fr))  }  .fg-text-muted {    color: var(--color-text-muted)  }  .font-regular {    font-weight: var(--font-weight-regular)  }  .gap-lg {    gap: var(--spacing-lg)  }  .m\(0\) {    margin: calc(0 * 1px)  }  .mt-xs {    margin-top: var(--spacing-xs)  }  .mb\(0\) {    margin-bottom: calc(0 * 1px)  }  .wrap-anywhere {    overflow-wrap: anywhere  }  .p-sm {    padding: var(--spacing-sm)  }}
兩張卡片的內容與元件 class 相同。第一張的內距為 24px;第二張加上 p-sm,在預覽的根字級為 16px 時,內距變成 12px。圓角、邊框與表面樣式都不變。

預設樣式集為一般宣告建立以下順序:

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

p-sm utility 的優先順序高於元件的內距宣告,與這個 class 在 HTML 屬性中的位置無關。串接規則說明了這個順序及其適用範圍。

這個 utility 只會改變內距,不會取代元件或移除其他宣告。因此,小幅的局部調整不需要新增元件變體,也不需要使用 !important。

#將原生規則放在正確的層

未放在任何層中的一般規則,優先順序高於具名層內的一般規則。如果 utility 已經編譯卻看不出效果,請檢查是否有未分層的元件規則:

/* This normal rule wins over a layered padding utility. */.collection-card {  padding: 1.5rem;}

如果這個共用規則應該允許 utility 覆寫,就將它移到 @layer components。不要只為了彌補非預期的分層方式而加上 !important。

未分層規則的優先順序高於一般分層規則

此處比較的是作者樣式中的一般宣告。帶有 !important 的宣告使用不同的層優先順序。

文字說明

圖中先將 components 排在 utilities 之前,再將未分層的規則獨立放在兩者上方。最後生效的內距來自該未分層規則。

分層不會取代串接的其他規則。是否帶有 !important 會先於一般層的優先順序決定結果,而且 !important 會反轉層與層之間的順序。行內宣告、動畫與轉場也各有其優先順序。這些規則請參閱 CSS 串接規範;預設樣式集的層順序則見 Master CSS 分層規則。

#找出互相競爭的宣告

  1. 在瀏覽器開發者工具中選取元素,到計算後的樣式中找到該屬性,再追查實際生效的宣告。
  2. 確認兩個規則都選中該元素,而且各自的條件都成立。
  3. 檢查每個宣告所屬的層,也要留意分層之外的原生 CSS。
  4. 加入局部覆寫之前,先將廣泛適用的預設樣式放回原本規劃的層。
  5. 如果只看層順序仍無法解釋結果,就繼續檢查 !important 與原生串接規則。

透過正常的 Master CSS 入口載入基礎樣式表。生成的規則會包含所屬的 layer 區塊,但不會自行加入基礎層順序的宣告。

將 collection-card p-sm 對調成 p-sm collection-card 無法解決問題:HTML 中的 class 順序不會控制串接結果。如果同一條件下的兩個 utility 互相重疊,可用程式碼檢查找出衝突,再決定要保留哪個宣告。