Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
13
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

posted at

updated at

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

最近、スマホで触れている間だけ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;
}
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
13
Help us understand the problem. What are the problem?