JavaScript
Sass
スマホ

スマホで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;
}