Skip to content

Sass 自訂函式 @function:回傳值而不是樣式

Sass 自訂函式 @function 的寫法

混入 產生 樣式,函式產生 。一句話劃清界線:

想把結果放進屬性值的位置 → 函式。想產生一整段宣告 → 混入。

定義與呼叫

scss
@use "sass:math";

@function rem($px, $base: 16px) {
  @return math.div($px, $base) * 1rem;
}

.title {
  font-size: rem(24px);   // 1.5rem
  padding: rem(8px) rem(16px);
}

@return 把值交出去,函式就結束了。呼叫時就像用內建函式一樣。

函式裡不能寫 CSS

scss
@function bad($x) {
  color: red;      // ❌ Error
  @return $x;
}

函式的內容只能是:變數指派、@if迴圈@debug / @warn / @error、以及 @return

多個 @return

搭配條件判斷,不同情況回傳不同的值:

scss
@use "sass:math";
@use "sass:color";

// 依背景色決定文字要用深色還是淺色
@function contrast-text($bg) {
  @if color.channel($bg, "lightness", $space: hsl) > 60% {
    @return #1a1a1a;
  } @else {
    @return #ffffff;
  }
}

.badge {
  background: #ffd43b;
  color: contrast-text(#ffd43b);   // #1a1a1a
}

執行到第一個 @return 就結束。每一條路徑都必須有 @return,漏掉某個分支會編譯錯誤。

幾個實用的函式

scss
@use "sass:math";
@use "sass:map";
@use "sass:meta";

// px 轉 rem
@function rem($px, $base: 16px) {
  @return math.div($px, $base) * 1rem;
}

// 從主題 map 取色,取不到就明確報錯
@function color-of($name) {
  @if not map.has-key($theme, $name) {
    @error "色彩 #{$name} 不存在,可用的有:#{map.keys($theme)}。";
  }
  @return map.get($theme, $name);
}

// 間距刻度:8px 的倍數
@function space($n) {
  @return $n * 8px;
}
scss
.card {
  padding: space(2);          // 16px
  color: color-of(primary);
  font-size: rem(18px);
}

這種取值函式比直接用 map.get() 好

color-of(primary) 打錯字時會得到一句清楚的錯誤訊息與可用清單;map.get($theme, primry) 只會安靜回傳 null,然後那一行宣告就消失了。錯誤訊息的寫法見 除錯

參數的規則與混入相同

預設值、關鍵字引數、任意參數的寫法完全一樣:

scss
@function clamp-size($min, $preferred, $max: 64px) {
  @return clamp(#{$min}, #{$preferred}, #{$max});
}

.hero {
  font-size: clamp-size($min: 24px, $preferred: 5vw);
}

細節見 混入的參數

命名要加前綴

自訂函式與 內建函式、未來的 CSS 函式都可能撞名:

scss
@function rem($px) { }      // ⚠️ 太通用
@function app-rem($px) { }  // ✅ 加專案前綴

@use 載入時本來就有命名空間(fn.rem()),衝突風險小很多;但若習慣用 as * 省略前綴,就更該自己加。

純函式:同樣的輸入永遠同樣的輸出

函式應該只依賴它的參數,不要去讀寫全域狀態:

scss
// ❌ 依賴外部變數,換個檔案結果就不一樣
$base: 16px;
@function bad-rem($px) {
  @return math.div($px, $base) * 1rem;
}

// ✅ 基準值也當參數,有預設值
@function rem($px, $base: 16px) {
  @return math.div($px, $base) * 1rem;
}

尤其不要在函式裡用 !global 改變數,理由見 變數旗標

常見問題

函式和混入該怎麼選?

看你要的是值還是樣式。需要一個可以放進屬性值位置的結果就寫函式,需要產生一整段宣告就寫混入。函式裡不能寫 CSS 規則,混入也不能回傳值。

函式可以寫 CSS 宣告嗎?

不行。函式的內容只能是變數指派、條件判斷、迴圈與 @return,寫進 CSS 宣告會直接編譯錯誤。函式的唯一產物就是它回傳的那個值。

自訂函式的名稱會和內建函式衝突嗎?

有可能,也可能與未來的 CSS 函式撞名。建議幫自訂函式加上專案前綴,例如寫成 app-rem() 而不是 rem(),模組系統的命名空間也能避免大部分衝突。

函式裡可以有多個 @return 嗎?

可以,搭配 @if 在不同分支各自回傳即可。執行到第一個 @return 就結束,後面的程式碼不會再跑。但每一條路徑都必須有 @return,否則會出現錯誤。

延伸閱讀