ボタンなどで良く使用する「hover」擬似クラスですが、スマホのブラウザではうまく動作しません。
スマホなどのタッチデバイスにはマウスホバーという概念がありません。
スマホでhoverのスタイルを実装するには少しコツが必要です。
hoverクラスのスタイルはスマホに反映されない
スマホなどのタッチデバイスでhoverスタイルがうまく反映されない主な理由は、タッチデバイスには「マウスオーバー」の概念がないためです。
chromeなどの一部のモバイルブラウザでは、タッチ操作をhoverイベントとして解釈しようとします。
例えば、ユーザーが要素をタッチすると、その要素に対して:hover
スタイルが適用されることがありますが、この挙動はブラウザやデバイス、バージョンによって一貫性がありません。
ブラウザのバージョンによっては:hover
スタイルが全く適用されないこともあるでしょう。(特にsafari)
ボタンが透明になるくらいの:hover
ならいいですが、下のようなマウスオーバーでメニューが表示されるような場合は、スタイルが適用されないと困りますよね。
そうならないよう対策をしていきましょう。
:hoverでメニューが表示されるサンプル
スマホの機種やブラウザによっては動作しません。
対策方法
ontouchstart属性(オススメ)
まずは最も簡単な方法としてontouchstart属性を指定する方法をご紹介します。
ontouchstart属性を使うことで、iOSやAndroid上でhover
効果を適用させることができます。
たとえば、マウスオーバーでボタンの色を変えるスタイルを実装している場合。
ボタンに対し、ontouchstart=""属性を指定します。属性の中身は空で構いません。
<a href="javascript:void(0);" class="btn" ontouchstart="">ボタンサンプル</a>
ontouchstart属性とは
ontouchstart
属性は、タッチスクリーンを持つデバイス(スマートフォンやタブレットなど)において、ユーザーが画面に触れた瞬間に発火するイベントを定義するために使用されます。
この属性を使用することで、ウェブページ上の要素に対してタッチイベントを捉え、それに応じた特定の動作やスタイルの変更を行うことができます。
では、なぜontouchstart
を使うとhover
スタイルが適用されるのでしょうか。
通常、hover
スタイルはマウスカーソルが要素の上に乗ったときに適用されるものですが、タッチデバイスではマウスカーソルが存在しないため、この挙動を直接的に再現することはできません。
ontouchstart
属性を要素に追加すると、その要素がタッチされたことをブラウザが検出し、タッチされた瞬間にイベントが発火します。このイベント発火をきっかけに、ブラウザはhover
スタイルをその要素に一時的に適用することがあります。
これは、タッチ操作をマウス操作の類似として解釈し、タッチされた要素に対してhover
スタイルを適用することで、タッチデバイスでも類似のビジュアルフィードバックを提供しようとするブラウザの挙動によるものです。
active疑似クラス
:hoverの代わりに:avtive疑似クラスを使用する方法です。
:active
疑似クラスは、要素がアクティブまたは「押された」状態であるときにスタイルを適用します。
タッチデバイス上では、ユーザーが要素をタッチしている間、この疑似クラスが適用されます。
<a href="javascript:void(0);" class="btn">ボタンサンプル</a>
/* スマホの時は:active */
@media screen and (max-width: 1000px) {
.dropdown {
opacity: 1;
}
.dropdown:active {
opacity: 0.7;
}
}
/* PCの時は:hover */
@media screen and (min-width: 1001px) {
.dropdown {
opacity: 1;
}
.dropdown:hover {
opacity: 0.7;
}
}
私もこの方法を試してみましたが、safariの場合長押ししないと反応しませんでした。
なのでactiveを使用する方法はあまり良くないですね。。
なら紹介するなよってね
:hoverと:active
:hover
ユーザーがマウスポインタを要素の上に置いたときに適用されます。
:active
要素がアクティブまたは「押された」状態にある間に適用されます。
ユーザーがリンクやボタンをクリックしている瞬間や、タッチスクリーンデバイスで要素をタップしている間に発生します。
touchstartイベント
touchstartとtouchendは、タッチスクリーンデバイスにおけるタッチイベントを扱うためのイベントタイプです。
これらのイベントを使用することで、ユーザーが画面をタッチしたときや、タッチを終了したときの動作を検知し、それに応じた処理を行うことができます。
:hoverと:active
touchstart
touchstart
イベントは、ユーザーが画面に指を置いた瞬間に発生します。このイベントは、タッチが開始されたときに特定の動作をトリガーするために使われます。例えば、ボタンがタッチされたことを検知して、特定のアニメーションを開始するといった用途が考えられます。
touchend
touchend
イベントは、ユーザーが画面から指を離した瞬間に発生します。タッチが終了したときに何かしらの動作を実行したい場合に便利です。例えば、タッチ操作によってアクティブになったボタンやリンクのアクションを完了させる、タッチによるドラッグ操作を終了するといった場合にtouchend
イベントが使用されます。
スマホで見れるサンプルを用意しました。
下のQRコードを読み込むとサンプルページに飛ぶことができます。
ソースを確認できるように、こちらに全コードおいておきます。
See the Pen Untitled by kokusyo (@kokusyo) on CodePen.
コード解説
コードの重要な部分だけ抜き出しています。
全コードは、上記のCoodPenよりご確認ください。
<div class="dropdown" id="dropdown">
<button class="dropbtn">メニュー</button>
<div class="dropdown-content">
<a href="#">リンク 1</a>
<a href="#">リンク 2</a>
<a href="#">リンク 3</a>
</div>
</div>
/* スマホデバイス用の「.hover 」クラスを付与したスタイル */
.dropdown.hover .dropdown-content {
opacity: 1;
transform: translateY(0);
}
.dropdown.hover .dropbtn {
opacity: 0.7;
}
/* PCデバイス用の「:hover」用のスタイル */
@media (hover: hover) {
.dropdown:hover .dropdown-content {
opacity: 1;
transform: translateY(0);
}
.dropdown:hover .dropbtn {
opacity: 0.7;
}
}
@media (hover: hover)はユーザーの入力機器がホバー機能を持つ(マウスオーバーなどで反応する)デバイスかどうかを判断するために使用されます。このメディアクエリは、主にPCのようにポインター(マウスカーソルなど)を使って操作するデバイスでhover
スタイルを有効にし、タッチベースのデバイス(スマートフォンやタブレットなど)でそれを無効にする場合に役立ちます。
// 要素を取得
var target = document.getElementById('dropdown');
// タッチ開始時のイベントリスナー
// タッチしている間hoverクラスを付与
target.addEventListener('touchstart', function () {
this.classList.add('hover');
});
// タッチ終了時のイベントリスナー
// タッチが終了したらクラスを削除
target.addEventListener('touchend', function () {
this.classList.remove('hover');
});
ボタンを押している間だけドロップダウンメニューが開くのが分かると思います。
touchstartイベントは主要なモバイルブラウザでサポートしています。
ただ押してる間しかメニュー開かないから、ドロップダウンメニューのボタン押せませんけどね。
clickイベント
touchstartとtouchendは、押してる間デザインを変えるだけならいいですが、ドロップダウンメニューのように押している間にメニューなどが開くスタイルの場合は、clickイベントで実装すると良いでしょう。
See the Pen Untitled by kokusyo (@kokusyo) on CodePen.
スマホでの確認はこちらから。
コード解説
PCの場合は、「hover」でドロップダウンメニューの表示。
スマホデバイスの場合は、クリックでドロップダウンメニューの表示を切り替えています。
ちなみに、今回はPCとスマホの判定を画面幅で設定しました。
/* スマホデバイス用の「.hover 」クラスを付与したスタイル */
.dropdown.hover .dropdown-content {
opacity: 1;
transform: translateY(0);
}
.dropdown.hover .dropbtn {
opacity: 0.7;
}
/* PCデバイス用の「:hover」用のスタイル */
@media (min-width: 768px) {
.dropdown:hover .dropdown-content {
opacity: 1;
transform: translateY(0);
}
.dropdown:hover .dropbtn {
opacity: 0.7;
}
}
// スマホの場合はクリックでドロップダウンを制御
if (window.matchMedia("(max-width: 767px)").matches) {
let dropdown = document.getElementById('dropdown');
dropdown.addEventListener('click', function () {
dropdown.classList.toggle('hover');
});
}
結論
いくつか方法を解説しましたが、どれも一長一短あるかなという感じです。
結局は最終的に、「どれがいいか」という問いに対する答えは、プロジェクト固有の要件に基づいて選択すべきという答えになります。
結論が自分で考えろだと味気ないので、私は普段こうしてるというのを書きます
●色を変えたり、画像のサイズを少し大きくするくらいのhoverには特に何もしません。
chromeなどのブラウザでは大体動作しますので。
●拘ったhoverの動きなど、多くの人に見てもらいたい場合は、ontouchstart=""属性を指定しています。
指定するだけなので簡単ですしね。
●ドロップダウンメニューなど、スマホでもちゃんと動作しないとまずいよね。
っていうものは、JavaScriptのイベントで実装しています。
ということで、「:hover」のスタイルをスマホでも動作させる方法でした。