SASS 中的繼承

SASS 中的繼承

本文將說明 SASS 中的繼承。

我們將用實際範例說明 SASS 的繼承。

YouTube Video

SASS 中的繼承

SASS 中的繼承(@extend)是一種機制,可以讓你將一個選擇器的樣式套用到另一個選擇器上,而不需重複撰寫樣式。由於相同樣式會被「合併」並輸出給標記中的多個元素,因此產生的 CSS 不易冗餘;但如果使用不當,可能會導致選擇器的意外合併。

基礎:如何使用 @extend

以下是一個基礎範例,.btn--primary 繼承了 .btn 的樣式。@extend 是用來擴展目標選擇器的指令。

 1// Base button styles
 2.btn {
 3  padding: 0.5rem 1rem;
 4  border-radius: 4px;
 5  border: 1px solid #ccc;
 6  background: white;
 7  color: #333;
 8}
 9
10/* Primary button extends the base .btn */
11.btn--primary {
12  @extend .btn;
13  background: #007bff;
14  color: white;
15}
  • 使用 @extend.btn--primary 可以繼承 .btn 的基礎樣式,只覆蓋必要的部分。

產生的 CSS

 1.btn, .btn--primary {
 2  padding: 0.5rem 1rem;
 3  border-radius: 4px;
 4  border: 1px solid #ccc;
 5  background: white;
 6  color: #333;
 7}
 8
 9.btn--primary {
10  background: #007bff;
11  color: white;
12}

最佳實踐:使用佔位選擇器(%placeholder

占位符選擇器(%name)是指不會被輸出到CSS中的選擇器。當你希望在多個元件之間安全共享僅用於繼承的共用樣式時,佔位符選擇器會被廣泛使用。

 1// %placeholder will not be output directly
 2%card-base {
 3  padding: 1rem;
 4  border-radius: 6px;
 5  box-shadow: 0 1px 3px rgba(0,0,0,0.08);
 6  background: #fff;
 7}
 8
 9/* Components extend the placeholder */
10.card {
11  @extend %card-base;
12  border: 1px solid #eee;
13}
14
15.panel {
16  @extend %card-base;
17  border: 1px solid #ddd;
18}
  • .card.panel 都從 %card-base 繼承,因此能共用基礎樣式並可根據需要加以擴充。

產生的 CSS

 1.card, .panel {
 2  padding: 1rem;
 3  border-radius: 6px;
 4  box-shadow: 0 1px 3px rgba(0,0,0,0.08);
 5  background: #fff;
 6}
 7
 8.card {
 9  border: 1px solid #eee;
10}
11
12.panel {
13  border: 1px solid #ddd;
14}

多重繼承(多個 @extend

你可以同時繼承多個佔位符或類別。雖然樣式的可重用性得到了提升,但追蹤哪些規則與哪些選擇器組合起來也非常重要。

 1%btn-base {
 2  display: inline-block;
 3  padding: 0.5rem 1rem;
 4  border-radius: 3px;
 5}
 6
 7%btn-large {
 8  padding: 0.75rem 1.5rem;
 9  font-size: 1.125rem;
10}
11
12/* Composite button that extends both placeholders */
13.btn--lg {
14  @extend %btn-base;
15  @extend %btn-large;
16  background: #222;
17  color: #fff;
18}
  • 以下是一個按鈕同時繼承兩個佔位符(基本樣式和尺寸樣式)的例子。
  • .btn--lg 同時繼承 %btn-base%btn-large,將基本佈局和大尺寸結合起來。

產生的 CSS

1.btn--lg {
2  display: inline-block;
3  /* %btn-large overrides the padding from %btn-base */
4  padding: 0.75rem 1.5rem;
5  border-radius: 3px;
6  font-size: 1.125rem;
7  background: #222;
8  color: #fff;
9}

@extend 的行為(合併機制)及『選擇器爆炸』的注意事項

@extend 會合併所有匹配的選擇器,有時會產生不預期的選擇器組合。

以下範例說明了同一個基礎類別在多個地方被擴展時,產出內容會暴增。

 1/* Many components extend .utility */
 2/* A generic utility class */
 3.utility {
 4  margin-bottom: 1rem;
 5}
 6
 7/* Nested selectors that extend .utility */
 8.header {
 9  @extend .utility;
10  .title {
11    font-weight: bold;
12  }
13}
14
15.footer {
16  @extend .utility;
17  .note {
18    color: #888;
19  }
20}
21
22.article {
23  @extend .utility;
24  .content {
25    line-height: 1.6;
26  }
27}
28
29.sidebar {
30  @extend .utility;
31  .section {
32    padding: 1rem;
33  }
34}
  • 當多個元件都繼承 .utility 時,選擇器會合併成一個,在大型專案內可能導致 CSS 過度膨脹。

產生的 CSS

 1.utility,
 2.header,
 3.footer,
 4.article,
 5.sidebar {
 6  margin-bottom: 1rem;
 7}
 8
 9.header .title {
10  font-weight: bold;
11}
12
13.footer .note {
14  color: #888;
15}
16
17.article .content {
18  line-height: 1.6;
19}
20
21.sidebar .section {
22  padding: 1rem;
23}

@extend.class vs. 元素選擇器(標籤)——優先級與副作用

@extend 不僅可以用於類別,也可以用於元素選擇器。然而,擴展元素選擇器會增加影響範圍,導致規則可能被意外應用到不希望的位置。

以下是一個擴展元素選擇器的例子,以及可能帶來的影響。

 1/* Extending an element selector (not recommended) */
 2h1 {
 3  font-size: 2rem;
 4  margin-bottom: 0.5rem;
 5}
 6
 7/* If you extend h1, the resulting selector will include your class with h1 */
 8.title {
 9  @extend h1;
10  color: #333;
11}
12
13/* Output becomes:
14h1, .title { font-size: 2rem; margin-bottom: 0.5rem; }
15*/
  • 在此例中,繼承元素選擇器 h1 使得 .titleh1 擁有相同的樣式。
  • 在小型專案中這看似方便,但隨著專案規模擴大,像是 h1 的規則可能會和 .title 意外結合,使樣式變得更複雜並降低可維護性。因此,主要以類別和佔位符為核心設計樣式會讓維護更容易。

產生的 CSS

1h1,
2.title {
3  font-size: 2rem;
4  margin-bottom: 0.5rem;
5}
6
7.title {
8  color: #333;
9}

@extend!optional 的應用場合

若在 @extend 後加上 !optional,當繼承目標不存在時可以抑制錯誤訊息。這在類似程式庫的程式碼或根據條件定義佔位符的情境下特別有用。

以下是一個安全地嘗試繼承可能不存在的類別、並使用 !optional 的範例。

1/* Try to extend a class that might not exist */
2.component {
3  @extend .maybe-existing !optional;
4  padding: 1rem;
5}
  • 如果 .maybe-existing 不存在,什麼都不會發生,並會被略過。當你需要安全地嘗試繼承時可以使用此語法。

產生的 CSS

1.component {
2  padding: 1rem;
3}

@extend 與混入(@mixin / @include)的比較

@extend@mixin 在某些情境下用途重疊,但輸出結果和適用場合不同。

  • @extend

    • 產生的 CSS 會通過合併選擇器減少冗餘。
    • 由於選擇器是在產生後合併,因此可能出現非預期的組合。
    • 無法傳遞參數(但可透過結合佔位符來補足)。
  • @mixin / @include

    • 每次呼叫都會重複產生樣式(導致冗餘輸出)。
    • 可傳遞參數並包含條件式、迴圈等邏輯。
    • 輸出較可預期,但檔案體積會增加。

以下對比用 @mixin@extend 實現相同按鈕樣式的範例。

 1/* Mixin approach */
 2@mixin btn-styles($bg, $color) {
 3  display: inline-block;
 4  padding: 0.5rem 1rem;
 5  background: $bg;
 6  color: $color;
 7  border-radius: 4px;
 8}
 9
10/* Use mixin */
11.btn {
12  @include btn-styles(white, #333);
13}
14
15.btn--primary {
16  @include btn-styles(#007bff, white);
17}
18
19/* Extend approach (shared placeholder) */
20%btn-base {
21  display: inline-block;
22  padding: 0.5rem 1rem;
23  border-radius: 4px;
24}
25
26.btn2 {
27  @extend %btn-base;
28  background: white;
29  color: #333;
30}
31
32.btn2--primary {
33  @extend %btn-base;
34  background: #007bff;
35  color: white;
36}
  • @mixin 可靈活插入樣式,@extend 則能高效合併輸出,可依情境選擇使用。

產生的 CSS

@mixin 的輸出
 1.btn {
 2  display: inline-block;
 3  padding: 0.5rem 1rem;
 4  background: white;
 5  color: #333;
 6  border-radius: 4px;
 7}
 8
 9.btn--primary {
10  display: inline-block;
11  padding: 0.5rem 1rem;
12  background: #007bff;
13  color: white;
14  border-radius: 4px;
15}
@extend 的輸出
 1.btn2,
 2.btn2--primary {
 3  display: inline-block;
 4  padding: 0.5rem 1rem;
 5  border-radius: 4px;
 6}
 7
 8.btn2 {
 9  background: white;
10  color: #333;
11}
12
13.btn2--primary {
14  background: #007bff;
15  color: white;
16}

實務指引

SASS 的繼承功能可以大幅提升樣式的重用性,是一個強大的功能。但若誤用,可能讓樣式合併變得複雜且降低維護性。以下是安全且高效使用繼承的幾個重點。

  • 對於純粹共用的元件樣式,例如結構和版面配置,請使用佔位符。另外,如果需要動態參數化,可以使用 @mixin
  • 應避免直接繼承像是 h1 這樣的 HTML 元素。可能會出現非預期的選擇器組合,導致產生意料之外的 CSS。
  • 採用 BEM 等命名規範或明確前綴標識每個佔位符的用途,有助於保持安全。
  • 在同一個檔案內使用 @extend 會比較安全。特別是在大型專案中,建議在每個元件的作用範圍內設計繼承,這有助於追蹤繼承關係。

總結

SASS 的 @extend 功能是一種高效重複利用共用樣式並確保設計一致性的便利方法。然而,選擇器組合很容易變得複雜,因此必須謹慎且限縮地使用這個功能。將共用樣式以佔位符選擇器(%placeholder)進行分組,並用 @mixin 處理需要動態參數的部分,可以維持簡單且易於維護的設計。

您可以在我們的 YouTube 頻道上使用 Visual Studio Code 來跟隨上述文章一起學習。 請也查看我們的 YouTube 頻道。

YouTube Video