[コピペで使える]作ってみて便利だった、Sassのコードまとめ

## この記事の内容
知人のホームページを作る仕事を引き受けました。
作業簡略化のため、諸々のsassを駆使してコードの記述量を減らしました。

その中で、次回HPを作るときのために保存したい！
と思うぐらい便利だったものを、まとめて紹介します。

なお、アルゴリズム的なことは大の苦手なので、
もう少し効率の良い書き方もあるかもしれません。

また、WEBデザイナーの方から見ると
「何コレ」「当たり前」的なものもあるかもしれません。

なお、`scss`ではなく`sass`を使って書いていますので、`scss`を使われる方は適宜読みかえてください。

## 8px, 16px ... などで margin, paddingを割り振ってくれるクラスをまとめて作成する
では、紹介していきます。

「ちょこっとここにスペースが欲しい...」というときに、全てにおいて意味のあるクラス名を作るのは難しいことがあります。
そんな時`bootstrap`の`.mt-1`, `.pb-2`のようなクラスが欲しいと思っていました。
そこで作ったのがこちら。

```sass
.u-
  $contexts: (m: margin, p: padding)
  @each $c-key, $context in $contexts
    &#{$c-key}
      $directions: (t: top, b: bottom, l: left, r: right)
      @each $d-key, $direction in $directions
        $amounts: 0, 8, 16, 24, 32, 40, 48
        @each $amount in $amounts
          &#{$d-key}-#{$amount}
            #{$context}-#{$direction}: $amount + px !important

// => .u-mb-0, .u-mt-8, .u-pl-16 etc...
```

これで、

- `.u-mb-0` ... margin-bottom: 0px
- `.u-mt-8` ... margin-top: 8px

...のようなUtilityクラスが一気に生成できます。
ただし、あまり作りすぎると大量のCSSが生成されることになるので、作りすぎに注意しましょう。

今見ると `$amount`の部分もループで回せそうですが、
何を生成しているのかわからなくなりそうなので、今回はここまでにします。

## ブレイクポイントを@mixinにまとめる
コレは多くの方が記事等に書かれている有名なコードになりますが、こんなコードです。

```sass
$breakpoints: (sm: 'all and (min-width: 576px)', md: 'all and (min-width: 768px)', lg: 'all and (min-width: 992px)', xl: 'all and (min-width: 1200px)', xxl: 'all and (min-width: 1400px)')

@mixin breakpoint-up($breakpoint)
  @media #{map-get($breakpoints, $breakpoint)}
    @content
```
コレによって、こんなsassを書くことが可能になります。

```sass:example
.hoge
  // 基本は赤色
  color: red
  @include breakpoint-up(sm)
    //576px以上で緑
    color: green
```
breakpointがHP内で揃いやすくなる上に、`min-width`なのか`max-width`なのかも揃い、非常に便利でした。

発想は、`bootstrap`の`media-breakpoint-up()`というmixinで、これが欲しいな〜と思って自作しました。

## displayプロパティの値をブレイクポイントごとに変えるクラスを作成する
また、上記の`breakpoint`のmixinを利用して作ったのがこちらです。

```sass
.u-d
  $values: none, block, flex, inline, inline-block
  @each $key, $breakpoint in $breakpoints
    &-#{$key}
      @include breakpoint-up($key)
        @each $value in $values
          &-#{$value}
            display: #{$value} !important
// => .u-d-md-none, .u-d-lg-flex etc...
```

これもBootstrapのdisplayユーティリティを真似て作りました。
ブレイクポイントごとに、
`display: none`や`display: flex`などを使い分けることができるクラスを生成します。

## 金属比（黄金比、白金比など）を計算
画像は全て白金比(1:1.732)か、ブロンズ比(1:3.303)にしていたのですが、途中から計算が面倒になってきてしまいました...。
そこで、横幅入れたら縦の大きさも自動計算してくれないかなーと思い、作ったのがこちらです。

```sass
@function m-raito($horizonal, $type)
  $m-raitos: (silver: 1.414, gold: 1.618, pl: 1.732, bronze: 3.303)
  @return $horizonal / map-get($m-raitos, $type) * 1px
```
こんな風に変数に横幅を入れたら縦幅を計算してくれます。

```sass
img
  $hr: 400
  width: $hr
  height: m-raito($hr, pl)
  // => height: 231px
```
金属比の比率そのものについては、[こちらのサイト](https://voidism.net/metallicratio/)利用させていただきました。

## ピクセルの値からremの値を出す
上記を思いついたきっかけになったのが、こちらの関数です。
こちらも本などにも載っている有名なものですが、、、、。
ピクセル数からremの値を計算してくれます。

```sass
$base-font-size: 16
@function rem($pixels, $context: $base-font-size)
  @return $pixels / $context * 1rem
```
使い方はこちらの通り。

```sass
span
  font-size: rem(12)
  // => font-size: 0.75rem
```
`rem(ピクセル数)`という形で、フォントサイズのピクセル数を`()`の中に入れると、該当する値をremで出力してくれます。

## z-indexを管理
コレも有名なやつですね...。
`z-index`に適当な値をつけていると、サイトが複雑になってきたときに、意図した順番にならないこともしばしば...。
そこで、こんな風にmixinを作成し、管理しやすくします。

```sass
$z-index: (modal: 100, nav: 30, btn: 5, layout: 1)
@mixin z-index($context)
  z-index: map-get($z-index, $context)
```
使い方はこちら。

```sass
.floating-btn
  @include z-index($btn)
// => z-index: 5 になる
```

## ホバーするとZoomするイメージの動きまとめ
特に何も凝った関数は使っていないですが、、、。大量に出てくる効果だったので、まとめたら大変コードがシンプルになりました。

```sass
@mixin img-zoom
  overflow: hidden
  img
    transform: scale(1)
    transition: .5s ease-in-out
    width: 100%
    &:hover
      transform: scale(1.1, 1.1)
```
このCSSでなぜzoomするイメージが出来上がるのかは、下記の記事が詳しいです。（タイトルは、原文ママ）

- [画像をhoverして時にズームさせるcssを書こう](https://weconet.co.jp/css_image_zoom/)

### 追記：@mixinではなくユーティリティクラスにするのが便利だった
こちらですが、「クリック可能な画像のみ、ホバーでzoomする」というルールで使っていたので、@mixinにするのではなく、下記のようにユーティリティクラスとして使用する方が汎用性が高く便利でした。

```sass
// リンクの中にある画像はズーム
a
  .u-img-zoom
    overflow: hidden
    img
      transform: scale(1)
      transition: .5s ease-in-out
      width: 100%
      &:hover
        transform: scale(1.1, 1.1)
```
@mixinだと、押せない画像にもzoomを適用してしまったり、あるいはコンポーネントの中身@mixinを埋め込んでしまったために後で打ち消したりと不便だったため、結局上記の@mixinは削除しました。

## 改善の余地ありだけどそこそこ使ったもの
ここからは、まだ改善の余地ありだとは思うけれども、そこそこに利用したものを列挙します。
次回WEB制作の仕事をするときの備忘録と、リファクタリング用のメモとして...。

### ページ全体に広がる要素のパディングを一定にする

ページ全体に100%で使用する要素は、footer, headerなど、いろいろありますよね。それらののpaddingを一定に揃えられないかと思い、次のようなmixinを作成しました。

```sass
@mixin page-px($size: sm)
  @if $size == sm
    padding:
      right: 16px
      left: 16px
  @else if $size == md
    padding:
      right: 40px
      left: 30px
  @else if $size == xxl
    padding:
      right: 48px
      left: 48px
```
`$size`の記述を`$breakpoints`の値と合わせるのがミソです。
こんな風に使うことで、要素の左右幅を一定に保つことができます。

```sass
.main-content
 @include page-px(sm)
 @include breakpoint-up(md)
  @include page-px(md)
```
#### 改善の余地がある点
途中、もう少し便利にできないかなと思い、
このようなmapを作成したものの...、あまり活用できませんでした...。

```sass
$page-paddings: (sm: (top: 14px, right: 16px, bottom: 40px, left: 16px), md: (top: 30px, right: 30px, bottom: 64px, left: 40px))
```
値を一つ取り出すにも、コレだけの記述量が必要でした。

```sass
map-get(map-get($page-paddings, sm), right)
```
もう少し上手くならないかなーと思います。

### コンテンツの下余白を一定に揃える
コンテンツ下部の余白は、見出し１、見出し２、セクション etc... で一定に揃えて、さらに画面幅に応じてそれらが２パターンあったのですが、それらを下記のようにまとめてみました。

```sass
$mb-maps: (sm: (pr: 8, h2: 8, h1: 16, section: 14, article: 32, content: 40), md: (pr: 8, h2: 16, h1: 32, section: 48, article: 80, content: 64))

%mb-
  @each $context, $mb-map in $mb-maps
    @each $element, $pixcel in $mb-map
      &#{$element}
        @if $context == sm or $context == false
          margin-bottom: $pixcel + px
        @else
          @include breakpoint-up(#{$context})
            margin-bottom: $pixcel + px
```
こちらの記述によって、このようなsassが利用できるようになるイメージです。

```css:sample
%u-mb-h1 {
  margin-bottom: 16px !important;
}

@media all and (min-width: 768px) {
  %u-mb-h1 {
    margin-bottom: 32px !important;
  }
}
```
%は`extend`専用セレクタですので、実際には出力されません。ただ、こちらはこのように使用することができます。

```sass
.c-header1
 @extend %u-mb-h1
```
こうすることによって、実際に出力されるCSSは下記の通りです。

```css:sample
.c-header1 {
  margin-bottom: 16px !important;
}

@media all and (min-width: 768px) {
  .c-header1 {
    margin-bottom: 32px !important;
  }
}
```
コレによって、大変記述量は減りました。よかったです。

#### 改善の余地がある点
何よりわかりにくい点です。最初のmapが複雑なのと、`%`という見慣れないセレクタも出てくるので、他の人と同時には使いにくいかな、と思います。。。

また、基本的に「見出し１」「見出し２」などのコンポーネントごとに１回しか使わないので、使用回数の割に作成の労力が大きかった気がします。。。

#### フォントサイズで使ってもなかなか便利でした
`font-size`プロパティも画面サイズによってさまざまに使い分けるので、同じように作成しましたが、なかなか便利でした。

```sass
$font-sizes: (sm: (caption: rem(12), small: rem(14), body: rem(16), h3: rem(18), h2: rem(18), h1: rem(22), page-title: rem(16)), md: (caption: rem(12), small: rem(14), body: rem(16), h3: rem(20), h2: rem(22), h1: rem(28), page-title: rem(28)))
%font-size-
  @each $context, $size-map in $font-sizes
    @each $element, $rem in $size-map
      &#{$element}
        @if $context == sm or $context == false
          font-size: $rem !important
        @else
          @include breakpoint-up(#{$context})
            font-size: $rem !important
```

使う時はこんな感じ。

```sass
.c-header1
  @extend %font-size-h1
```

## 感想
楽したい！の一心から、色々な関数を作ってしまいましたが、コレらのコードを書くのにむしろ時間がかかってしまったかもしれません:relaxed:
本業はエンジニアなのですが、次回WEBサイト制作を頼まれることがあったら、コレらのコードをコピペして、テキパキとサイトを作っていきたいです。

- 参考図書： [Web制作者のためのSassの教科書 改訂2版](https://www.amazon.co.jp/dp/B075LCKFLL/)
- 参考サイト： [Sass: Syntactically Awesome Style Sheets](https://sass-lang.com/)