Skip to content

Sass sass:meta 與 sass:selector:型別檢查與選取器操作

Sass 的 sass:meta 與 sass:selector 模組

這兩個模組平常用不到,但寫工具函式與元件庫時很關鍵:sass:meta 讓程式碼檢查自己的值與模組,sass:selector 讓你把選取器當資料操作。

sass:meta

scss
@use "sass:meta";

type-of:檢查型別

scss
meta.type-of(16px)        // number
meta.type-of("bold")      // string
meta.type-of(#2965f1)     // color
meta.type-of(true)        // bool
meta.type-of(null)        // null
meta.type-of((a, b))      // list
meta.type-of((a: 1))      // map

寫給別人用的 混入 一定要做參數檢查:

scss
@mixin square($size) {
  @if meta.type-of($size) != number {
    @error "square() 的 $size 必須是數字,收到 #{meta.inspect($size)}。";
  }
  width: $size;
  height: $size;
}

inspect:看清楚一個值

scss
@debug meta.inspect("primary");        // "primary"(含引號)
@debug meta.inspect(primary);          // primary
@debug meta.inspect((a: 1, b: (c: 2))); // (a: 1, b: (c: 2))

@debug 印一般值時會去掉引號,很難分辨 "bold"boldinspect() 會保留原貌,除錯 map 與引號問題時一定要用它。

其他檢查

scss
meta.variable-exists("brand")        // 目前範圍有沒有這個變數
meta.mixin-exists("center")
meta.function-exists("rem")
meta.global-variable-exists("brand")

寫相容多種環境的程式碼時偶爾會用到。

get-function 與 call

把函式當值傳遞:

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

@function apply-all($list, $fn) {
  $out: ();
  @each $x in $list {
    $out: list.append($out, meta.call($fn, $x));
  }
  @return $out;
}

$rounded: apply-all((1.2, 3.7), meta.get-function("round", $module: "math"));

load-css:動態輸出模組的 CSS

scss
@use "sass:meta";

$theme: "dark";

@include meta.load-css("themes/#{$theme}");
@usemeta.load-css()
路徑必須寫死可以用變數組
位置檔案最上方任何地方,含條件與迴圈
拿得到成員嗎拿得到拿不到,只輸出 CSS
可以帶設定嗎with$with 參數

它只輸出 CSS

load-css() 不會讓你使用對方的變數或混入。需要成員就得另外 @use

sass:selector

scss
@use "sass:selector";

組合選取器

scss
selector.nest(".card", ".title")        // .card .title
selector.nest(".a", "&:hover")          // .a:hover
selector.append(".btn", "--primary")    // .btn--primary
selector.replace(".a .b", ".b", ".c")   // .a .c

unify:兩者同時成立

scss
selector.unify("a", ".link")     // a.link
selector.unify(".a", ".b")       // .a.b
selector.unify("a", "span")      // null,一個元素不可能同時是兩者

判斷包含關係

scss
selector.is-superselector(".a", ".a.b")   // true,.a 涵蓋 .a.b

實際用途

寫元件庫時,混入需要程式化組出選取器:

scss
@use "sass:selector";

@mixin on-parent($parent) {
  @at-root #{selector.nest($parent, &)} {
    @content;
  }
}

.card {
  @include on-parent(".theme-dark") {
    background: #1a1a1a;
  }
}
css
.theme-dark .card { background: #1a1a1a; }

一般專案用不到這個模組

父選取器 &插值 就能處理九成以上的需求。sass:selector 是給需要把選取器當資料傳來傳去的場合用的。

常見問題

type-of 和 inspect 差在哪?

type-of() 回傳型別名稱,用來做參數檢查;inspect() 回傳值的原始樣貌字串,包括引號與 map 的完整結構,用來除錯時看清楚一個值到底長什麼樣。

load-css 和 @use 差在哪?

@use 是靜態的,路徑必須寫死且只能放在檔案最上方;load-css() 是函式,可以放在條件判斷或迴圈裡,路徑也能由變數組出來,但它只會輸出對方的 CSS,不會讓你拿到它的成員。

selector.unify 是做什麼的?

它把兩個選取器合併成一個同時符合兩者的選取器,例如把某個類別與 a 元素合併成 a 加上該類別。若兩者不可能同時成立,它會回傳 null

什麼時候會用到 sass:selector?

寫元件庫、需要程式化組合選取器的時候,例如根據傳入的父選取器組出巢狀路徑。一般專案很少用到,多數情況用父選取器與插值就夠了。

延伸閱讀