【JavaScript】スマホ専用のクリックイベントを設定する方法

「スマホのときだけクリック(タップ)で何かしたい」という要望はよくあります。ただし最初に知っておきたいのは、click イベントはPCでもスマホでも動くということです。

「スマホ専用」にしたいなら、もろいUA(ユーザーエージェント)判定ではなく、能力判定(matchMedia)で出し分けるのが現代的で確実です。この記事ではその正しいやり方を解説します。

この記事の結論:click はPC・スマホ両方で発火します。タッチ端末かどうかはmatchMedia("(pointer: coarse)")、画面サイズは matchMedia("(max-width: 768px)") で判定します。UA判定は非推奨(iPadがデスクトップUAを返すなど誤判定する)です。
スポンサーリンク

まず:clickはPCでもスマホでも動く

click イベントは、マウスのクリックでも指のタップでも発火します。つまり普通に click を設定すれば、スマホでもタップで動きます。「スマホ専用」にしたい場面は実は限られていて、多くは端末の能力に応じて挙動を変えたいだけのはずです。

JavaScript:clickは両方で動く
const button = document.getElementById("myButton");

button.addEventListener("click", () => {
  console.log("クリックでもタップでも発火します");
});

タッチ端末かどうかを判定する(matchMedia)

「タッチで操作する端末か」を判定するには、CSSメディア特性を読む matchMedia を使います。(pointer: coarse)(主ポインタが粗い=指タッチ)や(hover: none)(ホバーできない)で判定できます。

JavaScript:タッチ端末でだけイベントを設定
// 主ポインタが粗い(指タッチ)か
const isTouch = window.matchMedia("(pointer: coarse)").matches;

if (isTouch) {
  button.addEventListener("click", () => {
    console.log("タッチ端末でのみ実行");
  });
}

UA文字列に依存しないため、機種が変わっても壊れにくいのが利点です。matchMedia で画面サイズを扱う例は画面サイズをリアルタイムで取得する方法でも解説しています。

画面サイズで判定する(max-width)

「スマホ=小さい画面」とみなして画面幅で出し分ける方法もあります。CSSのブレークポイントと同じ条件で書け、画面幅が変わっても追従できます。

JavaScript:画面幅で判定
const mq = window.matchMedia("(max-width: 768px)");

function setup(e) {
  if (e.matches) {
    console.log("スマホ想定(小さい画面)の処理");
  } else {
    console.log("PC想定の処理");
  }
}

setup(mq);                          // 初期判定
mq.addEventListener("change", setup); // 幅が変わったら追従

ウィンドウ幅の条件で処理を分ける実装はウィンドウサイズの条件でページをリロードする方法も参考になります。

UA判定がなぜ非推奨なのか

古い記事では navigator.userAgent に「Mobi」「Android」が含まれるかで判定しますが、おすすめしません。次のように当てになりません。

JavaScript:非推奨なUA判定(NG)
// NG: もろいUA判定
function isMobile() {
  return /Mobi|Android/i.test(navigator.userAgent);
}
UA判定の問題点:iPadOS 13以降のiPadはデスクトップ用UA(Macintosh)を返すため、上の判定ではiPadが「非モバイル」と誤判定されます。② Androidタブレットも「モバイル」に含まれる。③ UAは偽装でき、仕様も時代とともに変化します。だからこそ、UAではなく matchMedia能力判定を使うのが安全です。

マウスもタッチも統一して扱う:Pointer Events

そもそも「端末を判定して分岐」しなくても、マウス・タッチ・ペンを統一して扱える Pointer Eventsがあります。イベントごとに pointerType で入力種別を見分けられます。

JavaScript:Pointer Eventsで入力種別を判定
button.addEventListener("pointerdown", (event) => {
  // "mouse" / "touch" / "pen" のいずれか
  console.log(event.pointerType);

  if (event.pointerType === "touch") {
    console.log("指で操作された");
  }
});

グローバルに「スマホかどうか」を判定するより、操作ごとに入力種別を見るほうが正確な場合が多いです。キーボードなど他の入力の扱いはキーボード入力を取得する方法も参考になります。

よくある質問(FAQ)

Qスマホでだけクリックイベントを動かすには?
AUA判定ではなく window.matchMedia("(pointer: coarse)").matches(タッチ端末か)で分岐してイベントを設定します。click 自体はPCでもスマホでも発火するため、能力判定で出し分けるのが確実です。
Qnavigator.userAgentでの判定ではダメですか?
Aおすすめしません。iPadOS 13以降のiPadはデスクトップUAを返すため誤判定し、UAは偽装でき仕様も変化します。matchMedia の能力判定(pointer / hover)を使ってください。
Qタップとスワイプを区別して処理するには?
Apointerdown(または touchstart)で座標を記録し、pointerup での差分が小さければタップ、大きければスワイプと判定します。方向は deltaXdeltaY の比較で分かります。
Qデスクトップとモバイルで共通のイベントを使うには?
APointer Events APIpointerdownpointermovepointerup)がマウス・タッチ・ペンを統一したAPIです。モダンブラウザで使えるため、新規実装に推奨されます。

まとめ

click はPC・スマホ両方で動くので、まず「本当に分岐が必要か」を考えましょう。必要な場合も、もろいUA判定ではなく matchMedia の能力判定(pointer: coarse) / (hover: none))や画面サイズ(max-width)で出し分けるのが確実です。

UA判定はiPadをデスクトップと誤認するなど当てにならず、非推奨です。マウスもタッチも扱いたいなら、Pointer EventspointerType を見るのが、もっとも正確で将来も安心な方法です。