Skip to content

Sass 混入 @mixin:定義一次、到處 @include

Sass 混入 @mixin 與 @include

混入(Mixin)把一段會重複出現的樣式包成一個名字,需要的地方用 @include 呼叫,整段就展開在那裡。它是 Sass 最常用的重用工具。

定義與呼叫

scss
@mixin center {
  display: flex;
  align-items: center;
  justify-content: center;
}

.modal {
  @include center;
  height: 100vh;
}

.avatar {
  @include center;
  border-radius: 50%;
}

編譯後:

css
.modal {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100vh;
}
.avatar {
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
}

沒有參數就不用括號

定義與呼叫都不必寫空括號。@include center; 即可。

它是複製,不是共用

上面的產出說明了混入的本質:@include 把樣式複製一份貼進去,兩個選取器各自擁有完整的宣告。

這一點常被拿來當缺點(產出會變大),但它同時也是優點:

特性影響
各自獨立的宣告順序可預測,不會受其他規則牽連
可以帶 參數同一個混入產出不同的值
可以在 @media 裡使用@extend 做不到這件事

重複的字串壓縮得很好

--style=compressed 加上伺服器的 gzip,重複宣告的體積成本比想像中小很多。除非是幾十個選取器共用一大段完全相同的樣式,否則不必為此改用 @extend

裡面可以放什麼

不只宣告,巢狀選取器、偽類、@media、甚至另一個 @include 都可以:

scss
@mixin card-base {
  padding: 16px;
  border-radius: 8px;
  background: #fff;

  &:hover {
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
  }

  @media (min-width: 768px) {
    padding: 24px;
  }

  .title {
    font-weight: 700;
  }
}

它就是一段被命名起來的樣式區塊,展開時原樣貼上,& 也會正確接到呼叫處的選取器。

混入也能巢狀呼叫

scss
@mixin visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
}

@mixin sr-only-focusable {
  @include visually-hidden;

  &:focus {
    position: static;
    width: auto;
    height: auto;
    clip-path: none;
  }
}

跨檔案使用

混入定義在 分部檔 裡,用 @use 載入後要加命名空間:

scss
// abstracts/_mixins.scss
@mixin center { /* ... */ }
scss
// components/_card.scss
@use "../abstracts/mixins" as mx;

.card {
  @include mx.center;
}

命名慣例

慣例範例
用動詞或效果命名centertruncatevisually-hidden
帶參數的說明用途respond-to($bp)text-style($size)
元件專用的加前綴btn-basecard-shadow
內部使用的加底線_reset-list,見 私有成員

該放哪個檔案

abstracts/
└── _mixins.scss     ← 全專案共用,且不產生任何 CSS
components/
└── _button.scss     ← 只有按鈕會用到的混入就放這裡

abstracts 裡的檔案不該有 CSS 規則

_mixins.scss 裡若寫了選取器,每個載入它的檔案都會多輸出一份樣式。那裡只放 定義,見 abstracts 該放什麼

常見的實用混入

scss
// 單行文字截斷
@mixin truncate {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

// 清除浮動
@mixin clearfix {
  &::after {
    content: "";
    display: block;
    clear: both;
  }
}

// 固定比例的容器
@mixin ratio($w, $h) {
  aspect-ratio: #{$w} / #{$h};
}

參數的完整用法見 混入的參數,把整段樣式傳進混入的做法見 @content

常見問題

混入會讓產出的 CSS 變大嗎?

會。@include 是把整段樣式複製一份貼進去,呼叫十次就出現十份宣告。不過壓縮與 gzip 對這種重複字串的效果很好,實務上多半不是問題,真正需要合併選取器時才考慮 @extend

混入裡面可以放選取器嗎?

可以。混入的內容不限於宣告,巢狀選取器、偽類、媒體查詢、甚至另一個 @include 都能放。它就是一段被命名起來的樣式區塊,展開時原樣貼上。

沒有參數的混入呼叫時要加括號嗎?

不用。寫成 @include center; 就好,加上空括號寫成 @include center(); 也合法但多餘。定義時同理,沒有參數就不必寫括號。

混入該放在哪個檔案?

全專案共用的放在 abstracts 目錄的 _mixins.scss;只有單一元件會用到的就放在該元件自己的檔案裡。放進 abstracts 的混入不該產生任何 CSS,這樣被載入幾次都不會多輸出樣式。

延伸閱讀