お勧めのメディアクエリのmixin:hover-media-query
この記事では、私がいつも使用しているメディアクエリのhover
のmixin
である
hover-media-queryについて紹介します。
hover-media-queryの概要
このパッケージの作者は、ブルガリアのバルナのデベロッパーAtanas Atanasovになります。
2021年4月にver1.0.0
が公開され、2022年1月現在はver1.1.0
となっており、比較的新しいパッケージになります。
:hover 擬似クラスの問題点
擬似クラスの:hover
のみだけで要素をスタイリングした場合、プライマリーインプットがマウスなどのホバー機能を持ったデスクトップの場合は問題ありませんが、スマホやタブレットなどのタッチスクリーンデバイスでは問題が発生します。下のMezo Istvanのブログにも紹介されているように、タッチスクリーンデバイスで要素をタップした際、タップ後もホバースタイルが適用され続けてしまいます。
MDNでも同様の内容が記載されており、スマホやタブレットなどのタッチスクリーンデバイスで、ホバースタイルが当てられた要素をタップすると、フラッシュ(ちらつき)の原因になったります。
この問題を解決するのが、Media Queries Level 4 (25 December 2021)のワーキングドラフトで定義されている、Interactin Media Featureになります。
Interaction Media Feature
には、3つのクエリがあります。
-
Pointing Device Quality
: the pointer feature(精度のクエリ) -
Hover Capability
: the hover feature(プライマリーインプットのホバー機能のクエリ) -
All Available Interaction Capabilities
: the any-pointer and any-hover features(すべてのポインティングデバイスとホバー機能に対するクエリ)
今回の:hover
擬似クラスの問題を回避する最適なクエリは、Hover Capability
になります。上記のMezo Istvan
のブログにも紹介されていますが、Surfaceなどのタッチスクリーンを搭載したラップトップにおいて、タッチパッド/キーボードを取り外すとタブレットモードになり、メディアクエリはそれを正しく処理すると書かれています。
使い方
これまで説明してきたHover Capability
を楽に導入する事ができるパッケージが、hover-media-queryになります。
ソースコードはとてもシンプルです。hover CSS Media Feature
をサポートしていない、IE10
/IE11
/Firefox before 64
も対象としています。
@mixin hover {
@media (hover: none) {
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
&:active {
@content;
}
}
@media (-ms-high-contrast: none), (-ms-high-contrast: active), (-moz-touch-enabled: 0), (hover: hover) {
&:hover {
@content;
}
}
}
あとは、ホバーしたい要素に@include
でmixin
を呼び出してhover
スタイルを適用します。下のコードはbutton
コンポーネントにhover
のメディアクエリを使用して、:hover
擬似クラスを適用した例になります。(hover-medea-query
のコードは、abstracts
ディレクトリ内で管理しています)
@use '../../abstracts/' as *;
/* base style */
.c-button {
display: inline-flex;
align-items: center;
justify-content: center;
width: 100%;
margin: 0 auto;
border-radius: 100vh; // rounded corners
// active style
&:active {
transform: translateY(fs-rem(1px));
}
// diabled style
&[disabled] {
opacity: 0.65;
pointer-events: none;
}
}
/* primary modifier */
.c-button--primary {
background-color: var(--color-neutral-lightest);
border: fs-rem(2px) solid var(--color-primary-mid);
transition: background-color 0.3s var(--ease-in-out-cubic);
// hover style
@include hover {
background-color: var(--color-primary-mid-alpha-high);
}
コンパイルした結果がこちらになります。
.c-button {
display: inline-flex;
align-items: center;
justify-content: center;
width: 100%;
margin: 0 auto;
border-radius: 100vh;
border-radius: calc(var(--vh, 1vh) * 100);
}
.c-button:active {
transform: translateY(0.0625rem);
}
.c-button[disabled] {
opacity: 0.65;
pointer-events: none;
}
.c-button--primary {
background-color: var(--color-neutral-lightest);
border: 0.125rem solid var(--color-primary-mid);
transition: background-color 0.3s var(--ease-in-out-cubic);
}
@media (hover: none) {
.c-button--primary {
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
.c-button--primary:active {
background-color: var(--color-primary-mid-alpha-high);
}
}
@media (-ms-high-contrast: none), (-ms-high-contrast: active), (-moz-touch-enabled: 0), (hover: hover) {
.c-button--primary:hover {
background-color: var(--color-primary-mid-alpha-high);
}
}
hover-media-query
のmixin
を使用することで、記述量を減らすことができるので助かっています。
ターゲットデバイスに適用されるメディアクエリの確認
ターゲットのデバイスがどのメディアクエリを適用するのかをテストするサイトがあります。下の画像は、私が使用しているMac Miniのテスト結果になります。主要な入力メカニズムがポインティングデバイスであり、ホバー機能を持っている事がわかります。
手元にある、Mac Mini
/iPad
/iPhone
/android
でテストしてみた結果が以下になります(iPad
/iPhone
/android
はタッチスクリーンでテストしています)。このようにしてターゲットデバイスに適用される、メディアクエリを確認する事もできます。
- | Mac | iPad | iPhone | android |
---|---|---|---|---|
@media(hover: none) | False | True | True | True |
@media(hover: hover) | True | False | False | False |
@media(any-hover: none) | False | True | True | True |
@media(any-hover: hover) | True | False | False | False |
@media(pointer: none) | False | False | False | False |
@media(pointer: fine) | True | False | False | False |
@media(pointer: coarse) | False | True | True | True |
@media(any-pointer: none) | False | False | False | False |
@media(any-pointer: fine) | True | False | False | False |
@media(any-pointer: coarse) | False | True | True | True |
参考記事
本記事を書くにあたり、以下の記事を参考にしました。
- Finally, a CSS only solution to :hover on touchscreens
- Interaction Media Features and Their Potential (for Incorrect Assumptions)
- Touch Devices Should Not Be Judged By Their Size
- MDN Web Docs @media hover
- MDN Web Docs @media any-hover
- MDN Web Docs @media any-pointer
最後に
ユーザーに混乱を与えるインタラクションをしないよう、適切にhover
のメディアクエリを適用する必要があります。hover-media-queryを活用することにより、数行のコードで:hover
擬似クラスの問題点を回避することができます。皆さんも試してみてください。
そして、hover-media-query
のmixin
を用意してくださった、Atanasさんに感謝いたします。
Discussion