今更ながらSass3.3で実装されたmap型の使い道を考えてみた

今回は3.3で導入されたMapというデータ型の使い道について気の向くままに書いてみました。
実際ネストと変数だけの為にSass(Scss)を利用しているところが多い(少なくとも自分はそのケースが多かった)ので、これをいい機会に組み込み関数やmixinfunctionなども利用したい所存です。
同じ境遇の人がこの記事を見て「使ってみたい!」となれば幸いです。

「2014年の8月にSass3.4リリースされたのに今更3.3の話か…」とか言わないでください。
(Sass Changelogを参照)

Sass3.3から導入されたデータ型「map」とは?

mapはSass3.3以降から導入されたデータ型で、JavaScriptの連想配列のようなデータ構造を作ることが出来ます。

$map: (
  black: #101010,
  red: #900,
  str: '文字列との混合も可能',
  // ネストも出来ます。
  orange: (
    light: #963,
    dark: #941
  ),
  // リストもカンマ区切り・スペ=ス区切りに対応
  list_comma: (a, b, c),
  list_space: a b c
);

map内の特定の値を取得するにはmap-get($map, $key)
キーのみ一覧取得するのであればmap-keys($map)(カンマ区切りで取得)、
値のみならmap-values($map)で取得できます。

mapには他にも以下の様な関数と、listに使われる関数(nth()length()など)も使用できます!

/*
各mapを結合する。
重複した場合はあとの方ので上書きされる
*/
map-merge($map1, $map2)

/*
map内に特定のキーがあるかを判定する。
返し値はboolean
*/
map-has-key($map, $key)

@eachとの相性

@eachはSass3.3から複数の変数を指定できるようになりました。
これと#{}によるシーケンスを使用することで、「class名(id名)に対応するプロパティを追加する」という処理を@eachで完結することが可能になりました。

// メインカラーとサブカラーをmapで管理
$colors: (
  primary: #400,
  secondary: #090
);

// mapの(key, value)の順で($name, $color)に値が入る
@each $name, $color in $colors {
  // シーケンスで$nameをクラス名に使う
  .box--#{$name} {
    background-color: $color;
  }
}

出力結果は以下のようになります。

.box--primary {
  background-color: #400;
}

.box--secondary {
  background-color: #090;
}

mapのメリット・デメリット

コード数が減る

背景画像だけ違うクラスを大量に作る時(ボタンのクラスなど)を作るときに利用すれば、ボタンの種類分コードが短くなる可能性があります。

(変数に格納するコードを書く分1行増えちゃうけど…)

コードの見通しがよくなる可能性がある

@forでは連番(0,1,2,…)による分岐が主でしたが、mapを使えばkey-value方式っぽく数値を利用できます。
keyに適切な名前を設定すれば、そのvalueが何なのかはっきりわかるようになり、連番よりもコードを理解しやすくなると思います。
(これは変数宣言全般に言えることですね。)

@each内のコード数が多いと見通しが悪くなる

組み込み関数などを利用する時は、CSSに出力した際にどのような結果となるかを考えながら利用しないといけないです。
@each@forはコード数は少なくなりますが、出力するコード量はmapの長さに比例するので、無駄なコードが出力されてないか、予期せぬclass名が付与されてないかを確認するのが少し面倒かもしれないです。

どこで使えば効果的か考えてみた

基本的な使い方はわかったところで、実際にどういう場面で使えるのか考えてみました。

ソーシャルボタンで使う

まず思いついたのがシェアボタンの実装です。

SNS名に対するブランドカラーを指定すれば、管理も楽&コード数がボタンの種類分減らせるかと思います!

ちなみに、このサイトの下にあるシェアボタンでもこの方法を使用しています。

$social_colors: (
  twitter: #1b95e0,
  facebook: #3b5998,
  google: #dd4b39,
  hatebu: #008fde,
  feedly: #6cc655,
  pocket: #ee4056
);

$btn_size: 64px;
.share__btn {
  display: block;
  margin: 10px auto;
  width: $btn_size;
  height: $btn_size;
}
@each $name, $color in $social_colors {
  .share__btn--#{$name} {
    background-color: $color;
  }
}

Media Queryで使う

自分でコードを少し書いてみたけどこんくらいなら普通に書いたほうが早いかもしれない…

.box {
  margin: 20px auto;
  height: 20px;
  background-color: #f91;
}

$device_width: (
  pc: 1200px,
  tablet: 720px,
  sp: 480px
);

@each $device, $val in $device_width {

  @media all and (max-width: $val) {

    .box.is-#{$device} {
      width: $val / 2;
    }

  }

}

BEMでのModifierに使う

BEMのModifierはmap型&@eachとの相性が抜群だと思います。
(よく考えると、だいたいの考え方はこれに帰着するのかも)

特に、色を変えるだけ、幅を変更する等のちいさな変化を記述するときにとても効果を発揮します。
また、@each内で@ifを利用すれば、特定のキーに対して別のプロパティを追加するなどの処理も可能です。

See the Pen map usage with @each by be-into (@be-into) on CodePen.

さいごに

他にも色々使い道はありそうですね。
「この使い方がアツい!」などがありましたら、是非教えて下さい。

現場からは以上です。

参考にしたサイトなど

  • BLOG
  • >
  • web
  • >
  • 今更ながらSass3.3で実装されたmap型の使い道を考えてみた