かゆいところに手が届くかもしれない sass mixin

## mixin便利！
もうsass無しじゃcss書けない体になりました。臨時追加。

## media query
sass mapと組み合わせて使うのが好きです。
####**`breakpoints.scss`**####
```scss
$sm: 600px;
$md: 900px;
$lg: 1200px;
$xl: 1800px;

$list: (
  sm: $sm,
  md: $md,
  lg: $lg,
  xl: $xl,
);
```
####**`mixins.scss`**####
```scss
@use 'sass:map';
@use './breakpoints.scss' as bp;

@mixin mq($direction, $breakpoint) {
  @if ($direction == 'below') {
    @media (max-width: #{map.get(bp.$list, #{$breakpoint}) - 0.1px}) {
      @content;
    }
  } @else if($direction == 'above') {
    @media (min-width: map.get(bp.$list, #{$breakpoint})) {
      @content;
    }
  }
}
```

使用例。

```scss
//画面サイズ599.9px以下で適用されるスタイル
@include mq(below, sm){
 //...
}

//画面サイズ900px以上で適用されるスタイル
@include mq(above, md){
 //...
}
```
引数の順序が逆の方がしっくり来る方もいるかもしれませんが、自分はこの順序の方が普通の英文みたいに読めるので好きです。(small belowよりbelow smallの方が直感的)

## on-hoverable-devices
hover可能なデバイスにのみスタイルを適用するmixin。

```scss
@mixin on-hoverable-devices {
  @media (hover: hover) and (pointer: fine) {
    @content;
  }
}
```

使用例。

```scss
@include on-hoverable-devices {
 //...
}
```
これくらい普通に書けって感じですが名前つけてmixinにしたほうが読みやすいので。

## on-non-hoverable-devices
上の逆ver.
hoverできないデバイスにのみスタイルを適用する。


```scss
@mixin on-non-hoverable-devices {
  @media (hover: none) and (pointer: coarse) {
    @content;
  }
}
```

## mouse-effects
hover、focusそしてactive状態のスタイルを指定します

```scss
@mixin mouse-effects($hover, $active, $change) {
  $things-to-change: (
    txt: 'color',
    bg: 'background-color',
  );
  @include on-hoverable-devices {
    &:hover,
    &:focus {
      @if ($hover == 'underline') {
        text-decoration: underline;
      } @else {
        #{map.get($things-to-change, $change)}: $hover;
      }
    }
  }
  &:active {
    @if ($active == 'underline') {
      text-decoration: underline;
    } @else {
      #{map.get($things-to-change, $change)}: $active;
    }
  }
}
```

使用例。

```scss
//hoverするとに文字が赤色に、activeの時は青色に
@include mouse-effects(red, blue, txt);

//hoverするとに背景が赤色に、activeの時は青色に
@include mouse-effects(red, blue, bg);

//hoverすると文字に下線を足し、activeの時はそれに加え文字が赤色に
@include mouse-effects(underline, red, txt);

//hoverすると背景が赤色になり、activeの時は文字に下線が追加される
@include mouse-effects(red, underline, bg);
```

このmixinの欠点は、一つの状態につき:

+ 文字色を変える
+ 背景色を変える 
+ 下線を足す

の**いずれか1つのみ**しか適用できないことです。

たとえばhover時に文字色を変えつつ下線を足したいという場合はこのmixinを2回使う必要があります。
こういう場合は素直に:hoverの中にスタイルを書きましょう。

ただ状態ごとに見た目がごちゃごちゃと変わらないデザインだと割と使用頻度は高いmixinです。

## aspect-ratio
[こちら](https://css-tricks.com/snippets/sass/maintain-aspect-ratio-mixin/)からの引用です。
まだcssのaspect-ratioプロパティがほとんどのブラウザでサポートされていないので。

```scss
@mixin aspect-ratio($width, $height) {
  position: relative;
  &:before {
    display: block;
    content: "";
    width: 100%;
    padding-top: ($height / $width) * 100%;
  }
  & > * {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
  }
}
```

使用例。

```scss
//アスペクト比を2:3に固定する
@include aspect-ratio(2, 3);
```

## padding-on-scroll-element
スクロール可能な要素において、スクロールした先のpaddingが適用されない問題を解決するためのmixin。

### 問題
以下のコードでは望んだ結果が得られません。

```html
<body>
  <div class="outer">
    <div class="inner">some text...</div>
  </div>
</body
```

```scss
body {
  max-width: 100vw;
  overflow: hidden;
}

.outer {
  height: 175px;
  overflow-x: auto;
  background: royalblue;
  padding: 20px; //うまく適用されない
}

.inner {
  background: teal;
  height: 100%;
  width: 120%;
}

```

#### 出力
右側のpaddingがありません。
![ezgif-2-feb6c93db22b.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/656202/f3019c89-73cc-560e-c242-81c540c6baf6.gif "右のpaddingが適用されない")

### 縦スクロールの場合
これに関してはpaddingが適用されるかどうかはブラウザごとに違うので、縦スクロールの場合にも対応できるmixinが必要です。

```html
<body>
  <div class="outer">
    <div class="inner">some text...</div>
  </div>
</body>
```

```scss
body {
  max-width: 100vw;
  overflow: hidden;
}

.outer {
  height: 175px;
  overflow-y: auto;
  background: royalblue;
  padding: 50px;
}

.inner {
  background: teal;
  height: 300%;
  width: 100%;
}
```

#### 出力
##### Brave Browser
![ezgif-1-6a2563f4aeb8.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/656202/1b71e143-7b5a-6875-7245-3633f5a7ea01.gif "Brave Browserでの出力")

##### Firefox dev edition
![ezgif-2-8346ada7b367.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/656202/e716b14e-f4dc-817e-b535-8599d4288163.gif "Firefox dev editionでの出力")


というわけでこれらの問題を解決してくれるmixinがこちらです。

```scss
@mixin padding-on-scroll-element($row: null, $column: null) {
  @if $row != null {
    padding-left: $row;
    padding-right: 0;
    &:after {
      content: '';
      padding-left: $row;
    }
  }
  @if $column != null {
    padding-top: $column;
    padding-bottom: 0;
    &:after {
      content: '';
      display: block;
      padding-top: $column;
    }
  }
}
```

表示されないpaddingの代わりに疑似要素差し込んでます。

使用例。

```scss
//横スクロールの場合
@include padding-on-scroll-element($column: 1em);

//縦スクロールの場合
@include padding-on-scroll-element($row: 1em);

//縦横どちらもスクロール可能な場合
@include padding-on-scroll-element($column: 1em, $row: 1em);
```

## padding-vertical/horizontal
上下/左右だけにpaddingがほしいときがよくあるので。
できればpadding-block/inlineを使いたいのですがブラウザサポートががが。

```scss
@mixin padding-vertical($padding) {
  padding-top: $padding;
  padding-bottom: $padding;
}

@mixin padding-horizontal($padding) {
  padding-left: $padding;
  padding-right: $padding;
}
```

使用例。

```scss
//上下
@include padding-vertical(1rem);

//左右
@include padding-horizontal(1rem);
```

## gap
flexboxのgapプロパティがまだあんまりサポートされていないので。
ちなみに親コンポーネントがflexじゃなくても使えます。

```scss
@mixin gap($row: null, $column: null) {
  @if $row != null {
    & > * {
      margin-right: $row;
    }
    & > *:last-child {
      margin-right: 0;
    }
  }
  @if $column != null {
    & > * {
      margin-bottom: $column;
    }
    & > *:last-child {
      margin-bottom: 0;
    }
  }
}
```

使用例。

```scss
//左右のgap
@include gap($row: 1rem);

//上下のgap
@include gap($column: 1rem);

//上下左右のgap
@include gap($row: 1rem, $column: 1rem);
```

## 最後に
以上、役に立つものがあれば幸いです。
なにか改善点などありましたらコメントください。