🧊

SassのMixinとPlaceholderの使い分け

ひとりケーススタディです。

前提として最近もやもや色々考えるけど、結局なんて結論付けたいかがよくわからんのが多いので、メモ書きってなニュアンス。

まずはおさらい。

Mixin

// いわゆる関数っぽい定義の仕方で
@mixin sample($color, $size) {
  background-color: $color;
  width: $size;
  height: $size;
}

// 使える
.sample {
  @include sample(blue, 30);
}

ほかにも、

// いわゆる関数っぽい定義の仕方で
@mixin sample($color, $size) {
  .sample {
    background-color: $color;
    width: $size;
    height: $size;
    @content; // コレに対して
  }
}

// ブロック投げ込める
@include sample(blue, 30) {
  text-align: center;
};

参考:File: SASS_REFERENCE — Sass Documentation

引数が受けられるのがポイント、と。

Placeholder

// いわゆるテンプレみたいなのを定義しておくと
%sample {
  background-color: white;
  width: 40px;
  height: 40px;
}

// そのまま拝借したり、上書きして使える
.sample {
  @extend %sample;
  background-color: red;
}

参考:File: SASS_REFERENCE — Sass Documentation

一見同じようにも見えますが、後述するとおり書きだされたCSSの中身がちょっと変わります。

ケーススタディ

というように、それぞれ用途があって存在する機能ってとこまではよし。
で、どっちを使うべきかという話になるケースってのは、どっちの機能でも満たせる要件って時なので・・。

  • 共通のスタイルを、使いたい箇所で使う
  • スタイルの上書きはするかもしれない

[1] Mixin

// _inc.scss
@mixin button($color) {
  color: $color;
  text-align: center;
  width: 100px;
  @content;
}
// main.scss
@import "./inc";

.main-container {
  .button {
    @include button(red) {
      height: 40px;
    };
  }
}
// main.css
.main-container .button {
  color: red;
  text-align: center;
  width: 100px;
  height: 40px;
}

Mixinはそのまんまで、使ったところで定義した内容が全部インクルードされる。
なのでインクルードしまくると、その分だけ重複したコードが増えていく。
動的にスタイルを上書きできる!ってのは良さそうに見えるけど、それPlaceholderでできるよ。

[2] Mixin

// _inc.scss
@mixin button($color) {
  .button {
    color: $color;
    text-align: center;
    width: 100px;
    @content;
  }
}
// main.scss
@import "./inc";

.main-container {
  @include button(red) {
    height: 40px;
  };
}
// main.css
.main-container .button {
  color: red;
  text-align: center;
  width: 100px;
  height: 40px;
}

これは[1]と大差ないんやけど、最近見かけたコードスタイルやったので一応載せてみる。
個人的にはピンときてなくて、そもそもなんてセレクタが展開されるか見えないとかありえんし、
Mixinって概念と定義の時点でクラスを吐き出すってのがもう本末転倒な気がして。

[3] Placeholder

// _inc.scss
%button {
  text-align: center;
  width: 100px;
}
// main.scss
@import "./_inc";

.main-container {
  .button {
    @extend %button;
    color: red;
    height: 40px;
  }
}
// main.css
.main-container .button {
  text-align: center;
  width: 100px;
}

.main-container .button {
  color: red;
  height: 40px;
}

コードが増えた風に見えるのは、Placeholderの仕様がそうなってるから。
Placeholderとして共通で使える部分が固められて、差分がそれぞれ増えていく。

Mixinで重複コードを増やす理由はないので、基本的にはコレを使うシーンが一番多いのではないかなーと思ってる。

まとめ

個人的には、明確に引数を受ける必要がある以外は、Placeholder使った方が良いのではないかなーと思う。

いわゆる共通のスタイルを継承して云々・・ってコンテキストで使うのはPlaceholderで、
いわゆる関数ライクにシンプルにコードを保ちたいときにはMixinを使う。

変に柔軟に対応できるように・・とかって高度な設計思想を持っても理解されなきゃ意味ないし、
多少雑でもそういう住み分けを徹底して設計するほうが、後で運用しやすいと思ってる。
選択肢を減らして考えさせないのが運用を楽にする勘所ってのが持論なので・・。

参考:Understanding placeholder selectors