Sass のカスタム関数の書き方

Sass は ネイティブ関数 のほかに、@function ディレクティブ を使ってカスタム関数を自由に定義することができます。僕もより共有や再利用のしやすいものを作るべく試行錯誤していますが、ここではそのうち最近試しているいくつかのパターンについて書いてみました。ご意見求む。

接頭辞

attr()calc() など CSS のネイティブ関数や percentage()type-of() といった Sass のネイティブ関数と名前が衝突するのを防ぐため、カスタム関数の関数名に接頭辞をつけることを検討しています。現行の CSS/Sass だけではなく将来追加される新しいネイティブ関数も考慮するとやはり何らかの対策をしておきたいところで、接頭辞は現実的な解であるように思います。Sass リファレンスの 関数ディレクティブの項 でも以下のように接頭辞の採用を勧めています:

It is recommended that you prefix your functions to avoid naming conflicts and so that readers of your stylesheets know they are not part of Sass or CSS. For example, if you work for ACME Corp, you might have named the function above -acme-grid-width.

もしライブラリのようなかたちで公開するものなら、例に挙げられているようにプロジェクト名を接頭辞にするとよさそうです。たとえば compass-grid-width() とか bourbon-grid-width() とか。もしくは Principles of writing consistent, idiomatic CSS で提案されているように x- が汎用的でいいかなと思うんですが、どうでしょう?

@function x-sprit-unit ($number) {
    // ...
}

@function x-convert-to-rem ($number) {
    // ...
}

エラー処理

渡された引数の型や単位などをチェックし、もし想定したものでない場合は戻り値を変更したり警告のメッセージを出力したりしています。例として数値から単位を取り除く関数を考えてみましょう (なおこの関数は Stack Overflowjsdo.it などを参考にしました)。

@function x-strip-unit ($number) {
    @return $number / ($number * 0 + 1);
}

この関数は引数として数値が渡されることを想定しているので、もし文字列が渡されるとエラーとなり、コンパイルに失敗します。そこで引数の型が数値かどうかチェックし、もし真なら本来の処理、偽なら @warn ディレクティブ で警告し、引数を処理せずそのまま返すようにしてみます:

@function x-strip-unit ($number) {
    @if type-of($number) == number {
        // 通常の処理
        @return $number / ($number * 0 + 1);
    } @else {
        // エラー処理
        @warn '#{ $number } is not a number.';
        @return $number;
    }
}

これでもいいんですが、@return ディレクティブは実行されると処理が関数の呼び出し元に戻る (つまり関数の残りは実行されない) ので、以下のように書くこともできます:

@function x-strip-unit ($number) {
    @if type-of($number) != number {
        // エラー処理
        @warn '#{ $number } is not a number.';
        @return $number;
    }
    // 通常の処理
    @return $number / ($number * 0 + 1);
}

複数の引数を多重にチェックする必要がある場合などはとくに、このようにエラー処理を前半にまとめるとコードの見通しが良くなります。

エラーの場合にどういった値を返すべきかは関数によって違ってくるでしょう。任意の引数をそのまま返すか、null を返すか、あるいは想定される値と見なして通常の処理をするか (たとえば単位の省略を許容するなど)、といったパターンが考えられます。

コメント

その関数がいったい何なのかについてコメントを残しておくと、チームのメンバーや未来の自分に感謝してもらえるのでおすすめです。書式はなんでもいいのですが、ほかのプロジェクトで使いまわすことなどを考えると、ある程度スタンダードに添っているといいかなと思い、JavaScript でわりと使われているらしい YUIDocJsDoc Toolkit あたりを真似たものを試してみてます。

// Strip unit from number
// @function x-strip-unit
// @param    {Number} $number number to strip unit
// @return   {Number} unitless number
// @example
//     x-strip-unit(-16px)        => -16
//     x-strip-unit(0.5em)        => 0.5
//     x-strip-unit(0.5cm + 10mm) => 1.5
@function x-strip-unit ($number) {
    // ...
}

機能についての簡単な説明に続けて関数名を示し、引数の型と識別子、戻り値の型、あと記述例などが書いてあるといいと思います。なおこれらのコメントは開発のためのものでコンパイル後には必要ないというか残ってるとおかしいので、/* */ 形式ではなく // 形式で。

もちろんこのコメントからドキュメンテーションが自動生成できると面白いんですが、そこまではできてないです。Ruby とか Node とかよくわかんないので… sassdoc ってプロジェクトもあるみたいですがどうなんでしょうね。でもコメントを残すだけでも充分有意義なはずです。

また Sass のドキュメンテーションとともに、CSS のスタイルガイドというものもちゃんとやんなきゃとずっと思いつつやれていないので、合わせて考えたいところですね (新年の抱負)。