13
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

スマホのhoverの動きをSassで矯正させるmixin

Last updated at Posted at 2019-02-07

最近、スマホで触れている間だけhoverするがチョコチョコいいねをして頂いて嬉しいが、中途半端なコードなので申し訳ないやら。
と、いうことでちゃんとしたのを書いてみました。

まとめたSCSSをGithubに置きます。

動作サンプルはめんどくさいので用意していません。あしからず。
古いバージョンだと&の扱い方が違うので正しく吐き出されないかもしれません。
Sass 4.0.0以降なら動作確認済みです。

Scss こんな書き方でスマホに対応できます

sample.scss
a {
  color: gray;
  @include hover {
    color: red;
  }
  @include active {
    color: green;
  }
}

準備

まずはじめにuserAgentでブラウザ&デバイス判別 2017年版 - QiitaGithubからユーザーエージェント判定用のスクリプトを拝借します。

index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Title</title>
<link rel="stylesheet" href="/css/style.css">
</head>
<body>
<div ontouchstart="">

</div>
<script src="/js/userAgentChecker.min.js"></script>
</body>
</html>

userAgentChecker.min.jsを読み込みます。
<div>をラッパーにして(全てを<div>で囲む)ontouchstart=""を記述します。
※ 何が条件なのか分からないが、<body ontouchstart="">では動かないことがあったので<div ontouchstart="">としたら動いたのでラッパーに与えた。
参考:タッチデバイスでCSSの:activeや:hoverを機能させる。 - Qiita

userAgentChecker.min.jsを読み込んだ時点で<html>class=""が付与されています。ここでタッチデバイス.touchか、マウス操作.mouseか分かる様になるので、これをCSSで利用します。

SCSS mixin

mixin/_hover.scss
@mixin hover ($touch: false, $highlight: false, $userSelect: false, $focus: true) {
  // mouse
  @at-root .mouse &:hover {
    @content;
  }
  @if $focus == true {
    @at-root .mouse &:focus {
      @content;
    }
  }
  // touch
  @if $touch == true {
    @at-root .touch &:active {
      @content;
    }
    // $highlight
    @if $highlight == false {
      -webkit-tap-highlight-color: rgba(#000, 0);
      appearance: none;
    }
    // $userSelect
    @if $userSelect == false {
      @at-root .touch & {
        user-select: none;
        input, select {
          user-select: auto;
        }
      }
    }
  } @else if $touch == false {
  } @else {
    @warn 'mixin hover $touchの値が正しくありません';
  }
}
mixin/_active.scss
@mixin active ($touch: true, $highlight: false, $userSelect: false) {
  $e: &;

  // mouse
  @at-root .mouse #{$e}:active {
    @content;
  }
  // touch
  @if $touch == true {
    @at-root .touch #{$e}:active {
      @content;
    }
    // $highlight
    @if $highlight == false {
      -webkit-tap-highlight-color: rgba(#000, 0);
      appearance: none;
    }
    // $userSelect
    @if $userSelect == false {
      @at-root .touch #{$e} {
        user-select: none;
        input, select {
          user-select: auto;
        }
      }
    }
  } @else if $touch == false {
  } @else {
    @warn 'mixin active $touchの値が正しくありません';
  }
}

mixin/_focus.scss
@mixin focus () {
  @at-root .mouse &:focus {
    @content;
  }
  @at-root .touch &:focus {
    @content;
  }
}

mixinを書きました。
:hover:activeを書くような感じで利用したかったので使い方は事項のようになります。

:focusを利用したいとき、:focus {}と書くとmixinで吐き出す.mouse a:hoverに優先度で負けてしまうので、頭に.mouse.touchをつけるだけのfocus用のmixinを作成しました。

mixinを利用

なにも考えずにmixinを利用すると以下のようになる。

style.scss
a {
  color: gray;
  @include hover {
    color: red;
  }
  @include active {
    color: green;
  }
}

コンパイル結果
a {
  color: gray;
  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
  -webkit-appearance: none;
     -moz-appearance: none;
          appearance: none;
}
.mouse a:hover {
  color: red;
}
.mouse a:focus {
  color: red;
}
.mouse a:active {
  color: green;
}
.touch a:active {
  color: green;
}
.touch a {
  -webkit-user-select: none;
     -moz-user-select: none;
      -ms-user-select: none;
          user-select: none;
}
.touch a input, .touch a select {
  -webkit-user-select: auto;
     -moz-user-select: auto;
      -ms-user-select: auto;
          user-select: auto;
}

autoprefixerを利用しているのでベンダープレフィックスがついています。
デフォルトではuser-select: none-webkit-tap-highlight-colorが透明、appearance: noneが付与されて出力されます。
上記CSSのon、offに加え、.touchのCSSがhoverと一緒なのかactiveと一緒なのかを引数で選択できるようにしています。

touch user-select -webkit-tap-highlight-color appearance focus
hover true/false true/false true/false true/false true/false
active true/false true/false true/false true/false -
focus - - - - -

※ 太字がデフォルト値
user-select, -webkit-tap-highlight-color, appearancetouchtrueのとき利用できる。

引数を利用したサンプル

style.scss
a {
  color: gray;
  @include hover (true, false, true) {
    color: red;
  }
  @include active (false) {
    color: green;
  }
  @include focus () {
  }
}

コンパイル結果
a {
  color: gray;
  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
  -webkit-appearance: none;
     -moz-appearance: none;
          appearance: none;
}
.mouse a:hover {
  color: red;
}
.mouse a:focus {
  color: red;
}
.touch a:active {
  color: red;
}
.mouse a:active {
  color: green;
}

こんな感じで簡単にスマホがタッチされたときの挙動をhoverではなく、感覚的なものに変更できたかと思います。

余談

iphoneでcolorの指定がないと、colorが背景色になるバグ発見!

a:hover {
  background-color: red;
}
13
13
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
13
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?