Sassでlinear-gradient()のmixinをつくる その6

このエントリはCSS Preprocessor Advent Calendar 2012の記事の続編です。

察せ。


Sass 3.3がついにリリースされました。リリースされないものだと思っていましたがよかったです。
アルファ版からインストールしていましたが、いまいち使っていませんでした。というわけで、これまで作ったMixinからSass 3.3の新機能を実際に使えないか試してみます。

Part 8: マップライクな処理はマップに置換え

linear-gradient()-webkit-linear-gradient()など接頭辞つきのバージョンとでは方向を示すキーワードが違います。対応関係があるためマップやハッシュで表現したいところですが、これまでのSassにはそういったものがなく、Sass 3.2の次に実装するとされていました。
そしてSass 3.3でついにマップが実装されました。わーい。

Sassのマップは(key1: value1, key2: value2)のように、ラベルつきのカンマ区切りリストみたいなかたちになってます。マップから値を取り出したりマップに値を追加したりする際には、新たに定義されたマップの関数を使います。

というわけで、キーワードの変換部分に使っていたマップライクな処理をマップに置換えてみます。
まずはキーワード版の処理を。こうなってました。

@mixin lg-keyword($keyword, $colorstops...) {
    $prefixes: '-webkit-';
    
    // 標準のキーワード
    $standard_keywords:
        to bottom, to left, to top, to right,
        to top left, to top right, to bottom right, to bottom left,
        to left top, to right top, to right bottom, to left bottom;
        
    // 接頭辞版のキーワード
    $legacy_keywords:
        top, right, bottom, left,
        bottom right, bottom left, top left, top right,
        right bottom, left bottom, left top, right top;
    
    // キーワードのインデックスを取得
    $idx: index( $standard_keywords, $keyword );
    
    // キーワードが不正な場合は何も出さない
    @if $idx {
        // マッチする接頭辞版のキーワードを取得
        $legacy_keyword: nth( $legacy_keywords, $idx );
        
        @each $prefix in $prefixes {
            background-image: #{$prefix}linear-gradient(
                $legacy_keyword, $colorstops);
        }
        background-image: linear-gradient($keyword, $colorstops);
    }
}

標準のキーワード、接頭辞版のキーワードを2つのリストにして、引数に与えられたキーワード(標準版)のインデックスを取得。出力時にそのインデックスを使い、接頭辞版のキーワードを引っ張ってきています。
これがマップを使うとこうなります。

@mixin lg-keyword($keyword, $colorstops...) {
    $prefixes: '-webkit-';

    $keywords_map: (
        to bottom:       top,
        to left:         right,
        to top:          bottom,
        to right:        left,
        to top left:     bottom right,
        to top right:    bottom left,
        to bottom right: top left,
        to bottom left:  top right,
        to left top:     right bottom,
        to right top:    left bottom,
        to right bottom: left top,
        to left bottom:  right top
        );

    // キーワードが不正な場合は何も出さない
    @if map-has-key($keywords_map, $keyword) {        
        @each $prefix in $prefixes {
            background-image: #{$prefix}linear-gradient(map-get($keywords_map, $keyword), $colorstops);
        }
        background-image: linear-gradient($keyword, $colorstops);
    }
}

(標準版: 接頭辞版, ...)というマップに作り直しました。引数が標準版のキーワードになっているかを調べるにはmap-has-key()関数を使えばOK。マップから値を取り出すときはmap-get()関数を使います。

ソースを整形してるため行数的にそんな変わってませんが、インデックスを取得するとかをしなくなったので、だいぶわかりやすくなったのではないかと思っています。
ただマップがマップとして読めない感はありますね…キーは内部的にリストとして扱われているので、括弧でくくってやるとちょっとはわかりやすくなるかな…うーん。

まとめ

とりあえずマップライクな処理を置換えても問題ないことがわかりました。他にもマップが使えるところがありますが、そちらはこれほどストレートフォワードではないので、また次回に。
えっ、次回…?

補足:-prefixed-linear-gradient()いるかい?

今回はlinear-gradient()から-webkit-linear-gradient()などの接頭辞版の構文互換の記述を吐き出すmixinを書きましたが、標準の構文がサポートされてからけっこう経ちます。

一番サポートが遅かったのはWebKitなのですが、こちらはSafari 7.0からサポートされています。Safari 6.0以前のサポートによって入れるか入れないかを決めてもよいのではないかと。あるいは-webkit-gradient()を吐き出すなら、特に入れなくてもいいのではないかと思います。