レスポンシブな汎用クラスを自動生成するSassのmixin

レスポンシブWebデザインでは汎用クラスにもブレイクポイントを指定しないと使いどころが難しいことがあります。例えば要素を`display:none;`で非表示にする汎用クラスの場合、ある程度ウィンドウサイズが大きくなってから非表示にしたい箇所も出てきます。

```css
.hidden {
  display: none;
}

@media screen and (min-width: 400px) {
  .hidden-sm {
    display: none;
  }
}
@media screen and (min-width: 768px) {
  .hidden-md {
    display: none;
  }
}
@media screen and (min-width: 1000px) {
  .hidden-lg {
    display: none;
  }
}
```

今回紹介するmixinを以下のように使用すると、レスポンシブな汎用クラスを簡単に生成することができます。

```scss
@include responsive(".hidden") {
  display: none;
}
```

## 変数
まず、ブレイクポイントを定義します。@eachを使用してブレイクポイントをループで取得するためにマップ形式で定義します。

```scss
$breakpoints: (
  'sm': 'screen and (min-width: 400px)',
  'md': 'screen and (min-width: 768px)',
  'lg': 'screen and (min-width: 1000px)',
) !default;
```

## mixin
mixinはこのように記述します。

```scss
@mixin responsive($class, $bp: $breakpoints) {
  #{$class} {
    @content;
  }
  @each $suffix, $value in $bp {
    @media #{$value} {
      #{$class}-#{$suffix} {
        @content;
      }
    }
  }
}
```

第一引数にclass名を渡します。ブレイクポイントなしのclassを生成、その後に@eachでブレイクポイント付きのclassが生成されます。マップ形式で定義した変数のkey（`sm`や`md`など）が接尾辞としてハイフン区切りで出力されます。

規則性をもったclassを簡潔に生成できるのが、このmixinのメリットだと思います。大元の変数やmixinを変更すれば、すべてに変更が適応されるので保守性にも優れています。

---

個人的にはブレイクポイントによって改行位置を変更したいときに、以下のような汎用クラスを生成しています。

```scss
@include responsive(".u-db") {
  display: block !important;
}

@include responsive(".u-di") {
  display: inline !important;
}
```

以下の場合では`span`に指定をしているので、スマホではインラインのまま、タブレット以上になるとブロックになり改行されます。

```html
<p>この文章の中で<span class="u-db-md">この部分は768px以上になると改行されます。</span></p>
```

## 危ない使い方

蛇足ですが、このmixinに変数と@eachをさらに組み合わせると`.mts`（`margin-top`のsmall）のようなマージンを調整するレスポンシブな汎用クラスを生成することもできます。

```scss
$margin-value: (
  '0': 0,
  's': 0.5rem,
  'm': 1rem,
  'l': 2rem,
) !default;

@each $name, $value in $margin-value {
  @include responsive(".u-ma#{$name}") {
    margin: $value;
  }
  @include responsive(".u-mt#{$name}") {
    margin-top: $value;
  }
  @include responsive(".u-mr#{$name}") {
    margin-right: $value;
  }
  @include responsive(".u-mb#{$name}") {
    margin-bottom: $value;
  }
  @include responsive(".u-ml#{$name}") {
    margin-left: $value;
  }
  @include responsive(".u-my#{$name}") {
    margin-top: $value;
    margin-bottom: $value;
  }
  @include responsive(".u-mx#{$name}") {
    margin-right: $value;
    margin-left: $value;
  }
}
```

```css
.u-ma0 {
  margin: 0;
}

@media screen and (min-width: 400px) {
  .u-ma0-sm {
    margin: 0;
  }
}
@media screen and (min-width: 768px) {
  .u-ma0-md {
    margin: 0;
  }
}
@media screen and (min-width: 1000px) {
  .u-ma0-lg {
    margin: 0;
  }
}

.u-mt0 {
  margin-top: 0;
}

@media screen and (min-width: 400px) {
  .u-mt0-sm {
    margin-top: 0;
  }
}
@media screen and (min-width: 768px) {
  .u-mt0-md {
    margin-top: 0;
  }
}
@media screen and (min-width: 1000px) {
  .u-mt0-lg {
    margin-top: 0;
  }
}
/* 中略 */

.u-mas {
  margin: 0.5rem;
}

@media screen and (min-width: 400px) {
  .u-mas-sm {
    margin: 0.5rem;
  }
}
@media screen and (min-width: 768px) {
  .u-mas-md {
    margin: 0.5rem;
  }
}
@media screen and (min-width: 1000px) {
  .u-mas-lg {
    margin: 0.5rem;
  }
}

/* 以降ずっと続く… */
```

ただし、この場合は564行という途方もない数のclassが生成されてしまいます。この時点で破綻してる感じがします。

Sassは強力なツールですが、CSSとしてどう出力されるのかを意識しておく必要がありますね。