JavaScript によるデバイスの判定のあれこれ
CSS の hover のスタイルをタッチデバイスとその他で分けたかったので、デバイスの判定についていろいろ調べる。
役に立ったリンク
繰り返します。ユーザーエージェントを調べるのが良いことはめったにありません。問題を解決するには、もっと良い、もっと広く互換性のある方法が見つかるはずです。
という注意書きがされているように、ユーザーエージェントによるデバイスの判定はできる限り避けて、他のアプローチでやったほうがいいよ、と。
すべて上記のリンクに書かれているが、結果として以下のような関数が出来上がった:
export const hasTouchScreen = () => {
if (navigator.maxTouchPoints > 0) {
return true;
}
if (navigator.msMaxTouchPoints > 0) {
return true;
}
if (window.matchMedia("(pointer:coarse)").matches) {
return true;
}
if ("orientation" in window) {
return true;
}
return false;
};
React Hook 化した場合は以下:
import { useEffect, useState } from "react";
import { hasTouchScreen } from "../utils/screen";
export const useHasTouchScreen = () => {
const [state, setState] = useState(false);
useEffect(() => {
setState(hasTouchScreen());
}, []);
return {
hasTouchScreen: state,
} as const;
};
コンポーネントで使う場合は以下:
import Link from "next/link";
import { useHasTouchScreen } from "../hooks/screen";
import styles from "./foo.module.scss";
const View: React.VFC = () => {
const { hasTouchScreen } = useHasTouchScreen();
return (
<>
<Link href="/">
<a className={`${!hasTouchScreen && styles.link}`}>Home</a>
</Link>
</>
);
};
export default View;
.link {
&:hover {
color: green;
}
}
これで画面をタッチで操作できないデバイスのみ hover すると Home リンクの文字が緑色になる。
画面をタッチで操作できるデバイスの判定をしている関数について詳しく見ていく。
export const hasTouchScreen = () => {
if (navigator.maxTouchPoints > 0) {
return true;
}
if (navigator.msMaxTouchPoints > 0) {
return true;
}
if (window.matchMedia("(pointer:coarse)").matches) {
return true;
}
if ("orientation" in window) {
return true;
}
return false;
};
navigator.maxTouchPoints
MDN Web Docs の説明によると以下のように書かれている。
Navigator インターフェイスの maxTouchPoints プロパティは読み取り専用で、現在の端末で対応している同時タッチコンタクト点の最大数を返します。
若干説明が分かりにくいが、画面をタッチで操作できるデバイスならば最低でも 1 になるので、それを判定する、という感じ。だいたいがこれでいけそう。
navigator.msMaxTouchPoints
例外として、msMaxTouchPoints というのがあるらしく、これについては調べても良い情報が出てこなかった。おそらく Windows 系の何かだろう。
window.matchMedia("(pointer:coarse)").matches
pointer の coarse というのは MDN Web Docs の説明によると
主要な入力メカニズムにポインティングデバイスがありますが、その正確性が限定されています。
と書かれているが、これはスマホやタブレットだと画面のタッチによる操作を指などでやるのでやや荒くなり、pointer の判定が coarse になるんだろうか。詳しくはわからない。
"orientation" in window
orientation というのは MDN Web Docs の説明によると
orientation は Screen インターフェイスの読み取り専用プロパティで、現在の画面の向きを返します。
と書かれており、スマホやタブレットだと縦画面や横画面であーだこーだできるので、それを「画面をタッチで操作できるデバイス」の判定でも利用できる、ということなんだろう。ただ、Screen.orientation は実験的な機能ですべてのブラウザには対応していないため、判定の優先度としては最後のほうに書くことになる。
Chrome DevTools を使うと端末のシュミレートができるので便利。Chrome DevTools での Device Mode によるモバイル端末のシミュレート