HTML5Experts.jp

Sass 3.3で追加された「関数」や「変更点」のまとめ解説

前二回の記事では、Sass 3.3で追加された「&」の新機能と@at-root新しいデータタイプ「マップ」について解説しました。

最後となる今回は、新しく追加された関数やいくつかの変更点を解説します。少し長くなりましたので目次を作りました。気になるところからお読みください。

新しく追加された関数

変更点

※Source Mapについては、丁寧に解説しているブログ記事が既にいくつかありますので、ここでは省略させていただきます。

文字列用の関数

新たに追加された文字列用の関数は6つあります。

str-length()

str-length()は、文字列の長さを取得する関数です。

// 引数には文字列を指定
str-length($string)

次のように使います。

str-length("foo")  //-> 3
str-length("")     //-> 0
str-length(" ")    //-> 1

str-length("漢字") //-> 2 str-length("ひらがな") //-> 4

str-insert()

str-insert()は、文字列の中の指定した位置に別の文字列を挿入する関数です。

// 引数の1つ目に対象となる文字列、
// 2つ目に挿入する文字列、3つ目に挿入する位置を指定
str-insert($string, $insert, $index)

次のように使います。

str-insert("abcd", "X", 1)
      //-> "Xabcd"
      //   第3引数を0にしても結果は同じ

str-insert("abcd", "X", 4) //-> "abcXd"

str-insert("abcd", "X", 5) //-> "abcdX"

第3引数には負の値を指定することができます。その場合、文字列の末尾からの位置になります。

str-insert("abcd", "X", -1)
      //-> "abcdX"

str-insert("abcd", "X", -3) //-> "abXcd"

また、第3引数に文字数を超える値を指定した場合は次のようになります。

str-insert("abcd", "X", 10)
      //-> "abcdX"

str-insert("abcd", "X", -10) //-> "Xabcd"

str-index()

str-index()は、文字列の中に指定された文字列が含まれているかどうかを調べる関数です。含まれている場合は開始位置を、含まれていない場合は0を返します。

// 引数の1つ目に文字列、2つ目に調べたい文字列を指定
str-index($string, $substring)

次のように使います。

str-index(abcd, b)   //-> 2
str-index(abcd, bc)  //-> 2
str-index(abcd, X)   //-> 0
str-index(abcd, ad)  //-> 0

大文字小文字は区別されます。

str-index(abcd, c)  //-> 3
str-index(abcd, C)  //-> 0

str-slice()

str-slice()は、文字列から指定した範囲を取り出す関数です。

// 引数の1つ目に対象となる文字列、
// 2つ目に取り出す開始位置、3つ目に終了位置を指定
// 3つ目を省略すると文字列の末尾までになる
str-slice($string, $start-at, [$end-at])

次のように使います。

// 2文字目から末尾まで
str-slice("abcd", 2)
     //-> "bcd"

// 2文字目から3文字目まで str-slice("abcd", 2, 3) //-> "bc"

// 0を指定した場合、1とみなされる str-slice("abcd", 0, 3) //-> "abc"

第2、3引数には負の値を指定することもできます。負の値を指定した場合、末尾からの位置になります。

// (末尾から)3文字目から2文字目まで
str-slice("abcd", -3, -2)
     //-> "bc"

// 2文字目から末尾から2文字目まで str-slice("abcd", 2, -2) //-> "bc"

第2引数より第3引数の値が小さい場合や同じ値の場合は「””」が返されます。 また、第2、第3引数が同じ位置を示す場合は、第2引数の位置の文字が返されます。

// 第3引数の値の方が小さい
str-slice("abcd", 2, 1)    //-> ""
str-slice("abcd", -3, -4)  //-> ""

// 引数の値が同じ str-slice("abcd", 2, 2) //-> ""

// 引数の値が同じ位置を示す str-slice("abcd", 2, -3) //-> "b"

to-upper-case()、to-lower-case()

to-upper-case()は文字列を大文字に、to-lower-case()は文字列を小文字にする関数です。

// 引数には文字列を指定
to-upper-case($string)
to-lower-case($string)

次のように使います。

to-upper-case(abcd)  //-> ABCD
to-upper-case(abCD)  //-> ABCD

to-lower-case(ABCD) //-> abcd to-lower-case(ABcd) //-> abcd

リスト用の関数

新たに追加されたリスト用の関数は2つあります。

list-separator()

list-separator()は、リストのセパレーターを返す関数です。

// 引数にはリストを指定
list-separator($list)

次のように使います。

list-separator(1px 2px 3px)      //-> space
list-separator((1px, 2px, 3px))  //-> comma

list-separator()の引数は1つなので、カンマ区切りのリストを上記のように直接指定する場合は、括弧(())で囲む必要があるので注意してください。

リストの要素が2つよりも少なく、セパレーターもない場合はspaceを返します。

// 要素が2つよりも少ない
list-separator('foo')     //-> space

// セパレーターがある list-separator(('foo',)) //-> comma

set-nth()

set-nth()は、n番目の要素を指定した値に置き換えた新しいリストを返す関数です。

// 引数の1つ目にリスト、2つ目に位置、3つ目に置換後の値
set-nth($list, $n, $value)

次のように使います。

$list: 10px 20px 30px 40px;

.sample { set-nth($list, 2, -20px); //-> 10px -20px 30px 40px

set-nth($list, -2, -20px);
    //-> 10px 20px -20px 40px

}

call()

call()は、動的に関数を呼ぶことができる関数です。 呼べるのは、Sassに組み込まれている関数とユーザーが定義した関数とCSSの関数です。

// 引数の1つ目に呼びたい関数、2つ目にその関数に渡す引数
call($name, $args...)

次のコードは、2つの引数を足した値を返すというサンプル用の関数です。

@function sum($a: 0, $b: 0) {
    @return $a + $b;
}

通常では次のように利用します。

.sample {
    margin: sum(1px, 2px);  //-> 3px
}

call()を使うと、次のようにしてsum()を利用することができます。

.sample{
    margin: call(sum, 1px, 2px);  //-> 3px

// call()の引数に変数を使う
$fn-name: sum;
padding: call($fn-name, 1px, 2px);  //->3px

}

また、キーワード引数を指定した場合、それはそのまま第1引数で指定した関数に渡されるため、次のようにすることもできます。

.sample {
    margin: call(sum, $b: 2px);  //-> 2px
}

call()の使い方次第では、より汎用性をもったミックスインや関数をつくることができそうです。

unique-id()

一度にコンパイルされたファイル内でユニークな、「u」から始まる9桁の文字列を返す関数です。文字列はコンパイルするたびに変わります。

.sample {
    content: unique-id();  //-> ucxkgyjv0
    content: unique-id();  //-> ucxkgyjva
    content: unique-id();  //-> ucxkgyjvc
    content: unique-id();  //-> ucxkgyjvg
}

変数、ミックスイン、関数の存在を調べる関数

variable-exists()

variable-exists()は、現在のスコープとグローバルスコープに指定された変数があるかどうかを調べる関数です。指定された変数がある場合はtrueを、ない場合はfalseを返します。

// 引数には変数名($は不要)を指定
variable-exists($name)

次のように使います。

$g-foo: "global foo";
.sample {
    $foo: "local foo";

// ローカル変数
content: variable-exists(foo);
    //-> true

// グローバル変数
content: variable-exists(g-foo);
    //-> true

// 存在しない変数
content: variable-exists(non-existent);
    //-> false

}

global-variable-exists()

global-variable-exists()は、指定されたグローバル変数があるかどうか調べる関数です。指定された変数がある場合はtrueを、ない場合はfalseを返します。

// 引数には変数名($は不要)を指定
global-variable-exists($name)

次のように使います。

$g-foo: "global foo";
.sample {
    $foo: "local foo";

// ローカル変数
content: global-variable-exists(foo);
    //-> false

// グローバル変数
content: global-variable-exists(g-foo);
    //-> true

// 存在しないグローバル変数
content: variable-exists(g-non-existent);
    //-> false

}

function-exists()

function-exists()は、関数があるかどうか調べる関数です。

// 引数には関数名を指定
function-exists($name)

次のように使います。

// サンプル用の関数
@function sample-fn() {
    @return true;
}

.sample { // ユーザー定義の関数 content: function-exists(sample-fn); //-> true

// Sassの組み込み関数
content: function-exists(lighten);
    //-> true

}

mixin-exists()

mixin-exists()は、ミックスインがあるかどうか調べる関数です。

// 引数にはミックスイン名を指定
mixin-exists($name)

次のように使います。

// サンプル用のミックスイン
@mixin sample-mixin() {
    /* ... */
}

.sample { // ユーザー定義のミックスイン content: mixin-exists(sample-mixin); //-> true

// 存在しないミックスイン
content: mixin-exists(non-existent);
    //-> false

}

inspect()

inspect()は、デバッグ用の関数です。

// 引数には調べたい値を指定
inspect($value)

CSSとして有効な値でなければコンパイルエラーになったり、変数に入れたnullやネストしたリストの括弧(())が出力されなかったりと、デバッグが簡単にはできませんでした。inspect()を使うことでこれらの問題を解決できます。

.sample {
    /* 変数に入れたnull */
    $var: 1px null 3px;
    content: $var;             //-> 1px 3px
    content: inspect( $var );  //-> 1px null 3px

/* 空のリスト */
$list: ();
content: $list;             //-> コンパイルエラー
content: inspect( $list );  //-> ()

/* ネストしたリスト */
$list: (1px, (foo (bar baz)), false);
content: $list;             //-> コンパイルエラー
content: inspect( $list );  //-> (1px, (foo (bar baz)), false)

/* マップ */
$map: (key1: value1, key2: value2);
content: $map;             //-> コンパイルエラー
content: inspect( $map );  //-> (key1: value1, key2: value2)

}

また、@debugにも同じ問題がありましたが、inspect()と同様に値を正しく表示するようになりました。

リスト関連

nth()

nth($list, $n)の$nに負の値を指定できるようになりました。負の値を指定するとリストの末尾からの位置になります。

これにより、リストの最後の値の取得が今までよりも簡単になりました。

$list: foo, bar, baz;

nth($list, -1) //-> baz

// 今まで… nth($list, length($list))

リストの最後のカンマ

カンマ区切りのリストで、最後にカンマを記述してもコンパイルエラーにならなくなりました。出力時には最後のカンマは取り除かれます。

$list: foo, bar, baz,;

@debug $list; //-> foo, bar, baz

また、マップも同じように最後にカンマを記述することができます。

$map: (
    key1: value1,
    key2: value2,
);

要素が1つしかないリストの生成

これまでは要素が1つしかないリストを作るのはかなり手間でした。

$list: ();     //-> list
$list: (1);    //-> number !!
$list: (1 2);  //-> list
$list: (1, 2); //-> list

// こうする必要があった $list: join( (), 1 ); //-> list $list: append( (), 1 ); //-> list

これからは次のようにするだけでリストとして扱われます。

$list: (1,);

ただし、カンマ区切りのリストになるので、スペース区切りのリストにしたい場合は次のようにします。

$list: join( (), 1, space);
$list: append( (), 1, space);

@each

前回の記事でも少し触れていますが、複数の変数を利用することができるようになりました。

$config: (
    warn: red,
    info: blue,
);

@each $class, $bg-color in $config { .#{$class} { background-color: $bg-color; } }

これをコンパイルすると次のようになります。

.warn {
  background-color: red;
}

.info { background-color: blue; }

if()

if()は三項演算子みたいな感じのものですが、これまではなぜかtrue/falseの両方の戻り値を評価していたため少し使い勝手が悪いものでした。これからは、条件の結果がtrueならtrueの戻り値だけ評価するようになります。

@extend

@media内で外にあるセレクタを@extendすると、警告ではなくコンパイルエラーとなるように変更されました。

@media screen {
    .foo {
        @extend .bar;
    }
}

.bar { ... }

また、存在しないセレクタを@extendした場合も、警告ではなくコンパイルエラーとなります。!optionalフラグを記述するとコンパイルエラーを回避することができます。

.foo {
     @extend .non-existent !optional;
}

!globalフラグ

ローカル(ネスト内)でグローバル変数と同名の変数に代入する場合、グローバル変数の値が変更されていましたが、それがデフォルトの挙動ではなくなります。そのような場合、将来的には、新しいローカル変数が作られて処理されることになり、グローバル変数を上書きする場合には「!global」フラグをつけて明示することが必要になるようです。Sass 3.3.0.rc.2でも「!global」フラグをつけないと警告が表示されてしまいます。

$var: true;

.sample { // グローバル変数を上書きしたい場合 $var: false !global; ... }

おわりに

師走だからというわけではありませんが、いろいろと駆け足で解説しました。筆者としてはライブラリに使えるものが増えたので嬉しいのですが、普通の制作には不要なものも少なくないと思います。無理に使ってみるのではなく、必要に応じて取り入れることをお勧めします。

よいお年を。