はじめに
PCでの見た目を整えるために :hover でボタンの背景色を変えるスタイルを書いた。Chromeで確認したら期待通りに動いている。ところがiPhoneで開いてボタンをタップすると、指を離した後もそのボタンだけ色が変わったままになり、次に別の場所をタップするまで貼り付いたように残ってしまう。
この記事では、なぜタッチデバイスで :hover が残留するのか、そしてPCとタッチデバイスの両方で自然に振る舞わせる書き方を解説します。
何が起きているか
マウスを使うPCでは、カーソルが要素の上に乗っている間だけ :hover が適用され、離れれば即座に解除されます。「ホバー」はもともとマウスカーソルの位置を前提にした概念です。
しかしタッチデバイスにはカーソルという概念がありません。それでもWebサイト側は :hover を前提にしたスタイルを大量に書いているため、iOS Safariはタップの瞬間を一時的に「その要素にカーソルが乗った」状態として扱い、:hover を適用します。その後、画面の別の場所をタップするか、ページがスクロールされるまでホバー状態は解除されません。
/* PCではタップ相当の操作をした要素にだけ:hoverが適用される。
iOS Safariではタップした要素にこのスタイルが貼り付いたまま残る */
.btn:hover {
background: #3b82f6;
color: #fff;
}
PC用に何も考えずに書いた :hover は、iOS Safariでは「タップした要素の見た目が変わったまま戻らない」不具合として現れます。
修正方法: hoverが使えるデバイスにだけ適用する
解決策は、:hover をメディアクエリで囲み、実際にマウスなどのポインティングデバイスでホバー操作ができる環境にだけ適用することです。
@media (hover: hover) and (pointer: fine) {
.btn:hover {
background: #3b82f6;
color: #fff;
}
}
hover: hover は「ホバー操作が可能なポインティングデバイスがあるか」を判定するメディア特性です。マウスやトラックパッドを使うPCでは真になり、タッチのみのスマートフォンでは偽になります。pointer: fine(正確な位置決めができるデバイスかどうか)も併記しておくと、スタイラスペン対応のタブレットなど境界的な環境でも意図通りに絞り込めます。
これで、PCではこれまで通り :hover が効き、タッチデバイスでは最初から :hover が適用されなくなるため、タップ後に色が残ったままになる現象自体が起きなくなります。
タッチデバイス側のフィードバックは:activeに分離する
:hover を無効化しただけだと、タッチデバイスではボタンを押した反応が一切なくなってしまいます。押した瞬間のフィードバックは :active に役割を分けて用意します。
.btn:active {
background: #1d4ed8; /* :hoverより少し濃い色にしておくと押した感が出る */
color: #fff;
}
:active はタップ中(指を触れている間)だけ適用され、離せば即座に解除されるため、:hover のように残留する問題は起きません。タップ時のフィードバックそのものについては、タップ時の灰色ハイライトが残る原因と消し方もあわせて確認しておくと、ボタンまわりの実装が一通り揃います。
デモで確認する
ホバーの残留はタッチ操作特有の挙動なので、PCのマウス操作では再現できません。お手元のiPhoneで下のボタンをタップし、指を離した後の見た目を確認してください。
「崩れるパターン」のボタンをiPhoneでタップすると、指を離した後もボタンが青いままになります。「修正パターン」ではタップした瞬間だけ色が変わり、指を離すとすぐに元の見た目に戻ります。PCでマウスを使っている場合は、どちらのボタンもカーソルを乗せている間は同じように色が変わります。
まとめ
iOS Safariで :hover がタップ後も残るのは、タッチ操作を一時的にホバー状態として扱う仕様が原因です。@media (hover: hover) and (pointer: fine) で :hover をホバー可能なデバイスに限定し、タッチデバイス向けの反応は :active に分けて実装すれば、PCでもiPhoneでも自然な見た目になります。すでに書いてしまった :hover スタイルを一律で見直す場合は、既存のセレクタをそのままメディアクエリで囲むだけで対応できます。
コピペで使える正解パターン
/* ===== PCでのみホバースタイルを効かせる ===== */
@media (hover: hover) and (pointer: fine) {
.btn:hover {
background: #3b82f6;
color: #fff;
}
}
/* ===== タップ・クリック中の共通フィードバック ===== */
.btn:active {
background: #1d4ed8;
color: #fff;
}
最後まで読んでいただきありがとうございました。
関連するUI事例
hoverスタイルを使う代表的なUI事例です。いずれもコピペで動くサンプルを掲載しています。
同じiOS Safariシリーズの記事もあわせてどうぞ。