メインコンテンツまでスキップ

hoverを指定するならany-hoverメディア特性を使いなさい!俺流hover実装例も紹介します

CSS

広告

タップデバイスでもhoverが動いているWebサイトが多すぎる!

hoverを指定するならany-hoverメディア特性を使いなさい

前提として、タップデバイスでのhoverアクションは次のようなデメリットから無効化すべきです。

  • タップデバイスでhoverアクションを用いると、タップ後にhover状態が継続し、UIの予期しない振る舞いやユーザー体験の混乱を招く可能性がある
  • デバイスによってはhoverが指定されている要素はダブルタップしないと反応しない可能性がある

タップ操作orポインター操作の区別を行うための方法はいくつかありますが、現在ではhoverメディア特性が全モダンブラウザでサポートされているためこちらを利用しましょう。

/* 🙆‍♂ Recommended */
@media (any-hover: hover) {
.button:hover {
background-color: var(--background-hover);
}
}

hoverメディア特性には@media (hover: hover)@media (any-hover: hover)の2種類があります。

  • @media (hover: hover): 主な入力デバイスがhoverに対応している場合に適用する
  • @media (any-hover: hover): 入力デバイスのいずれかにhoverに対応している入力デバイスが含まれる場合に適用する

少し前までは@media (hover: hover) and (pointer: fine)で「主な入力デバイスがhoverに対応していて、かつマウスのような正確なポインターがあるデバイスの場合」にのみhoverを適用するやり方を行っていましたが、この方法ではiPadのMagic Keyboardのカーソル操作でhoverが適用されないようです。

そのため、Magic Keyboardが接続されている時のみhoverが適用され、解除されるとhoverが適用されなくなる@media (any-hover: hover)を利用したほうがカバーできる範囲が増えるため良さそうかなという印象です。

ただし、キーボードが接続されている時のタップ操作の判定はメディア特性ではできないため、そういった場合をケアするのならJSで判別を行う必要があります。ただし、メディア特性で大勢はカバーできるのでそこにコストを掛けるのかは各々の判断にお任せしますと言ったところでしょうか。

hoverの無効化をメディアクエリのwidthでやったつもりになってはいけない

ポインターデバイスとタップデバイスの分岐のやり方としてよくある誤りがメディアクエリのwidthで行うことです。

/* 🙅‍♂ Not Recommended */
@media (width < 640px) {
.button:hover {
background-color: var(--background-hover);
}
}

理由としては画面幅が小さいポインターデバイスもあれば画面幅が大きいタップデバイスも存在するからです。上記のような指定だとiPadでhover動いちゃいますよね。

俺流hover実装例

当ブログ含む僕のhoverの実装例ですが、大体このような形になっています。

.button {
transition: background-color 0.3s;
}
.button:focus-visible {
background-color: var(--background-hover);
}
@media (any-hover: hover) {
.button:hover {
background-color: var(--background-hover);
}
}

前提として、これは過去の有料noteとかでも触れていますがtransition-propertyの値はアニメーションで動くものだけに絞る。transition: 0.3s;のようにtransition-propertyの記述をサボると初期値がall故にブレイクポイント跨いだ時に意図しないアニメーションが起こる可能性があります。transition-propertyの値の指定は必須です。マスト。

続いて、:hoverで行っているものと同じ指定を:focus-visibleにも適用するようにしています。キーボード操作時にフォーカスされている要素を明確に示したいという意図があるからです。フォーカスリングの色が背景色と似ている場合、フォーカスリングが見えにくくなる可能性がありますし、フォーカスリングは要素の外側に表示されるため、親要素に意図しないoverflow:hiddenが指定されたりすると最悪フォーカスリングが隠れてしまうリスクもあります。

そして前述した@media (any-hover: hover)を利用する。というのがhover実装のルーティンとなっています。