3
6

More than 3 years have passed since last update.

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

Last updated at Posted at 2021-05-18

mixin便利!

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

media query

sass mapと組み合わせて使うのが好きです。

breakpoints.scss

$sm: 600px;
$md: 900px;
$lg: 1200px;
$xl: 1800px;

$list: (
  sm: $sm,
  md: $md,
  lg: $lg,
  xl: $xl,
);

mixins.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;
    }
  }
}

使用例。

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

//画面サイズ900px以上で適用されるスタイル
@include mq(above, md){
 //...
}

引数の順序が逆の方がしっくり来る方もいるかもしれませんが、自分はこの順序の方が普通の英文みたいに読めるので好きです。(small belowよりbelow smallの方が直感的)

on-hoverable-devices

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

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

使用例。

@include on-hoverable-devices {
 //...
}

これくらい普通に書けって感じですが名前つけてmixinにしたほうが読みやすいので。

on-non-hoverable-devices

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

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

mouse-effects

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

@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;
    }
  }
}

使用例。

//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

こちらからの引用です。
まだcssのaspect-ratioプロパティがほとんどのブラウザでサポートされていないので。

@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;
  }
}

使用例。

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

padding-on-scroll-element

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

問題

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

<body>
  <div class="outer">
    <div class="inner">some text...</div>
  </div>
</body
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

縦スクロールの場合

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

<body>
  <div class="outer">
    <div class="inner">some text...</div>
  </div>
</body>
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

Firefox dev edition

ezgif-2-8346ada7b367.gif

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

@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の代わりに疑似要素差し込んでます。

使用例。

//横スクロールの場合
@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を使いたいのですがブラウザサポートががが。

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

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

使用例。

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

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

gap

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

@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;
    }
  }
}

使用例。

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

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

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

最後に

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

3
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
6