【JavaScript】スマホとPCを判定して処理を切り替える方法|matchMedia・userAgent・タッチ判定・実装パターンまで解説

【JavaScript】スマホとPCを判定して処理を切り替える方法|matchMedia・userAgent・タッチ判定・実装パターンまで解説 JavaScript

スマホではハンバーガーメニュー、PC ではドロップダウンメニュー。スマホではスワイプ操作、PC ではホバー。このようにデバイスに応じて処理を切り替える場面は頻繁にあります。

本記事では、デバイス判定の4 つの方法と、それぞれのメリット・デメリットスマホ / PC で処理を切り替える実装パターンまで解説します。

この記事でわかること
・matchMedia で CSS のブレークポイントと連動して判定する方法
・navigator.userAgent で端末種別を判定する方法
・navigator.maxTouchPoints でタッチ対応を判定する方法
・navigator.userAgentData.mobile(Chromium 系)
・4 方式の比較と使い分け
・ウィンドウリサイズに追従するレスポンシブ判定
・スマホ用メニュー / スワイプ / ホバーの出し分けパターン
スポンサーリンク

デバイス判定の 4 つの方法

方法 判定対象 メリット デメリット
matchMedia(推奨) 画面幅 CSS ブレークポイントと統一。リサイズ追従 PC でウィンドウを狭めるとモバイル判定になる
userAgent 端末の種類 実際のデバイスを判定 文字列パースが煩雑。詐称可能
maxTouchPoints タッチ対応 物理的なタッチ能力を判定 タッチ対応 PC(Surface 等)を誤判定
userAgentData.mobile モバイルフラグ ブラウザが正確に宣言 Chromium 系のみ対応
「何を判定したいか」で方法を選ぶ
レイアウトの切り替え(メニューの表示形式等)→ matchMedia(画面幅)
端末の物理的な種類(iPhone / Android / PC)→ userAgent
タッチ操作の可否(スワイプ / ホバー)→ maxTouchPoints
モバイルかどうかの単純な判定(Chromium 系限定)→ userAgentData.mobile

matchMedia で画面幅で判定する(推奨)

JavaScript(matchMedia: 基本)
// CSS のブレークポイント(768px)で判定
const isMobile = window.matchMedia("(max-width: 768px)").matches;

if (isMobile) {
  console.log("モバイル表示");
  initHamburgerMenu();
} else {
  console.log("PC 表示");
  initDropdownMenu();
}
JavaScript(matchMedia: リサイズに追従)
// ウィンドウリサイズ時にも判定を更新(レスポンシブ対応)
const mql = window.matchMedia("(max-width: 768px)");

function handleDeviceChange(e) {
  if (e.matches) {
    console.log("モバイルに切り替わった");
    initHamburgerMenu();
  } else {
    console.log("PC に切り替わった");
    initDropdownMenu();
  }
}

// 初回判定
handleDeviceChange(mql);

// リサイズ時に自動で再判定
mql.addEventListener("change", handleDeviceChange);
matchMedia が最も推奨される理由
・CSS のブレークポイントと同じ基準で判定できる(768px / 1024px 等を統一)
addEventListener("change") でリサイズに自動追従
・ブラウザに依存しない(userAgent のパースが不要)
・タブレットの扱いもブレークポイントで自然に解決

userAgent で端末種別を判定する

JavaScript(userAgent でスマホ / PC を判定)
// スマートフォンの判定(iPhone / Android スマホ)
function isSmartphone() {
  const ua = navigator.userAgent;
  return /iPhone|Android.*Mobile/i.test(ua);
}

// タブレットの判定(iPad / Android タブレット)
function isTablet() {
  const ua = navigator.userAgent;
  // iPadOS 13+ は Mac として報告されるため別途判定
  const isIPad = navigator.platform === "MacIntel"
    && navigator.maxTouchPoints > 1;
  return isIPad || /Android(?!.*Mobile)/i.test(ua);
}

// PC の判定(スマホでもタブレットでもない)
function isPC() {
  return !isSmartphone() && !isTablet();
}

console.log("スマホ:", isSmartphone());
console.log("タブレット:", isTablet());
console.log("PC:", isPC());
iPadOS 13+ は userAgent で判定できない
iPadOS 13 以降の Safari は Macintosh として報告され、iPad が userAgent に含まれません。navigator.maxTouchPoints > 1 との組み合わせで判定してください。

maxTouchPoints でタッチ対応を判定する

JavaScript(タッチ対応の判定)
// タッチデバイスかどうか
function isTouchDevice() {
  return navigator.maxTouchPoints > 0
    || "ontouchstart" in window;
}

if (isTouchDevice()) {
  // タッチ操作用の処理
  enableSwipeNavigation();
} else {
  // マウス操作用の処理
  enableHoverEffects();
}
タッチ対応 PC に注意
Surface、タッチ対応ノート PC など、マウスとタッチの両方に対応するデバイスが増えています。isTouchDevice() が true でも「スマホ」とは限りません。タッチ判定は「タッチ操作を有効にするか」の判断に使い、レイアウトの切り替えには matchMedia を使ってください。

userAgentData.mobile(Chromium 系限定)

JavaScript(userAgentData: 最もシンプル)
// Chromium 系ブラウザ(Chrome / Edge / Opera)のみ
if (navigator.userAgentData) {
  console.log("モバイル:", navigator.userAgentData.mobile);   // true / false
  console.log("プラットフォーム:", navigator.userAgentData.platform); // "Android" / "Windows" 等
}

// フォールバック付き判定
function isMobile() {
  if (navigator.userAgentData) {
    return navigator.userAgentData.mobile;
  }
  return /iPhone|Android.*Mobile/i.test(navigator.userAgent);
}

ブラウザ判定の詳細は「ブラウザを判定する方法」を参照してください。

統合的なデバイス判定関数

JavaScript(統合判定: matchMedia + フォールバック)
// matchMedia ベース + タッチ判定 + userAgent フォールバック
function getDeviceType() {
  // (1) matchMedia(画面幅ベース: レイアウト向け)
  const isNarrow = window.matchMedia("(max-width: 768px)").matches;
  const isMedium = window.matchMedia("(min-width: 769px) and (max-width: 1024px)").matches;

  // (2) タッチ対応
  const hasTouch = navigator.maxTouchPoints > 0;

  if (isNarrow) return "smartphone";
  if (isMedium && hasTouch) return "tablet";
  return "desktop";
}

const device = getDeviceType();
console.log(device); // "smartphone" / "tablet" / "desktop"

// body にクラスを付与して CSS でも活用
document.body.classList.add(`is-${device}`);

CSS だけで出し分ける方法(JS 不要)

表示の切り替えだけなら JavaScript を使わずCSS メディアクエリだけで対応できます。

CSS(メディアクエリで出し分け)
/* PC 用メニュー: 768px 以下で非表示 */
.desktop-menu {
  display: flex;
}
@media (max-width: 768px) {
  .desktop-menu { display: none; }
}

/* スマホ用メニュー: 768px 以下でのみ表示 */
.mobile-menu {
  display: none;
}
@media (max-width: 768px) {
  .mobile-menu { display: block; }
}

/* ホバーが使えるデバイスのみ */
@media (hover: hover) {
  .card:hover { transform: scale(1.05); }
}

/* タッチデバイスのみ */
@media (pointer: coarse) {
  .btn { min-height: 48px; } /* タップしやすいサイズ */
}
メディアクエリ 対象
(max-width: 768px) 画面幅 768px 以下(スマホ)
(min-width: 769px) 画面幅 769px 以上(タブレット + PC)
(hover: hover) ホバーが使えるデバイス(PC のマウス)
(hover: none) ホバーが使えないデバイス(タッチのみ)
(pointer: coarse) タッチ操作(指で操作)
(pointer: fine) 精密なポインター(マウス / トラックパッド)
hover: hover / pointer: coarse は CSS だけでタッチ判定できる
JavaScript でタッチ判定する代わりに、CSS の @media (hover: hover) でホバー効果を出し分けたり、@media (pointer: coarse) でタップ領域を大きくしたりできます。表示の出し分けだけならCSS だけで完結させるのが最もシンプルです。

実務パターン集

パターン(1): スマホ用ハンバーガーメニュー / PC 用ナビバー

JavaScript
const mql = window.matchMedia("(max-width: 768px)");

function setupMenu(e) {
  if (e.matches) {
    // スマホ: ハンバーガーメニュー
    document.querySelector(".hamburger").hidden = false;
    document.querySelector(".nav-desktop").hidden = true;
  } else {
    // PC: 通常ナビバー
    document.querySelector(".hamburger").hidden = true;
    document.querySelector(".nav-desktop").hidden = false;
  }
}

setupMenu(mql);
mql.addEventListener("change", setupMenu);

パターン(2): タッチデバイスでスワイプ、PC でドラッグ

JavaScript
const hasTouch = navigator.maxTouchPoints > 0;

if (hasTouch) {
  // タッチ操作: touchstart / touchmove / touchend
  slider.addEventListener("touchstart", onTouchStart);
  slider.addEventListener("touchmove", onTouchMove);
  slider.addEventListener("touchend", onTouchEnd);
} else {
  // マウス操作: mousedown / mousemove / mouseup
  slider.addEventListener("mousedown", onMouseDown);
  slider.addEventListener("mousemove", onMouseMove);
  slider.addEventListener("mouseup", onMouseUp);
}

// Pointer Events なら 1 つのコードで両方対応可能(推奨)
slider.addEventListener("pointerdown", onPointerDown);
slider.addEventListener("pointermove", onPointerMove);
slider.addEventListener("pointerup", onPointerUp);
Pointer Events でタッチとマウスを統一
pointerdown / pointermove / pointerup はタッチとマウスの両方に対応するイベントです。タッチとマウスを個別にハンドリングする必要がなくなるため、新規開発では Pointer Events を推奨します。

パターン(3): PC のみホバーでツールチップ表示

JavaScript
// ホバーが使えるデバイスのみツールチップを有効化
if (window.matchMedia("(hover: hover)").matches) {
  document.querySelectorAll("[data-tooltip]").forEach(el => {
    el.addEventListener("mouseenter", showTooltip);
    el.addEventListener("mouseleave", hideTooltip);
  });
}

パターン(4): スマホで遅延読み込みの閾値を変更

JavaScript
// スマホは通信量を節約するため早めに遅延読み込み
const rootMargin = window.matchMedia("(max-width: 768px)").matches
  ? "200px"   // スマホ: 200px 手前で読み込み
  : "500px";  // PC: 500px 手前で読み込み

const observer = new IntersectionObserver(callback, { rootMargin });

パターン(5): body にデバイスクラスを付与

JavaScript
// ページ読み込み時にデバイスクラスを付与
// CSS でも JS でも活用できる
const mql = window.matchMedia("(max-width: 768px)");

function updateDeviceClass(e) {
  document.body.classList.toggle("is-mobile", e.matches);
  document.body.classList.toggle("is-desktop", !e.matches);
}

updateDeviceClass(mql);
mql.addEventListener("change", updateDeviceClass);

// CSS で活用: body.is-mobile .sidebar { display: none; }

よくある質問

QmatchMedia と userAgent はどちらを使うべきですか?
Aレイアウトの切り替え(メニュー、カラム数等)なら matchMedia が最適です。CSS のブレークポイントと統一でき、リサイズにも追従します。端末の物理的な種類(iPhone なのか Android なのか)を知りたい場合は userAgent を使います。
QPC でブラウザ幅を狭めるとモバイル判定になるのは問題ですか?
A通常は問題ありません。matchMedia は「画面幅」で判定するため、PC でウィンドウを狭めればモバイルレイアウトに切り替わります。これは CSS のレスポンシブデザインと同じ動作であり、むしろ一貫性があります。
QタブレットはスマホとPCのどちらとして扱うべきですか?
Aプロジェクトの要件によりますが、画面幅で判断するのが最もシンプルです。768px〜1024px をタブレット帯として扱うか、768px 以下を全てモバイルとして扱うかをチームで決めてください。matchMedia なら (min-width: 769px) and (max-width: 1024px) でタブレット帯を定義できます。
QPointer Events は全ブラウザで使えますか?
AIE 11 を含むほぼ全てのモダンブラウザで使えます。タッチイベント(touchstart 等)とマウスイベント(mousedown 等)を別々に書く必要がなくなるため、新規開発では Pointer Events を推奨します。
QCSS の hover: hover と JavaScript のタッチ判定はどう使い分けますか?
A見た目の変更(ホバー効果の有無)は CSS の @media (hover: hover) で対応。イベントハンドラの切り替え(スワイプ / ドラッグの登録)は JavaScript の maxTouchPoints で対応。表示の出し分けだけなら CSS で完結させるのが最もシンプルです。
Qサーバーサイドでデバイスを判定するべきですか?
Aレスポンシブデザインならサーバー側の判定は不要です(CSS + JS で対応)。サーバーサイドレンダリング(SSR)で HTML 自体を出し分けたい場合は、User-Agent ヘッダーをサーバー側でパースします。ただしキャッシュが複雑になるため、クライアント側判定の方がシンプルです。

まとめ

デバイス判定と処理の切り替えの要点をまとめます。

やりたいこと 推奨方法
画面幅でレイアウトを切り替え matchMedia(“(max-width: 768px)”)
リサイズに追従する判定 matchMedia + addEventListener(“change”)
タッチ操作の有無を判定 navigator.maxTouchPoints > 0
ホバー効果の出し分け CSS @media (hover: hover)
タップ領域の拡大 CSS @media (pointer: coarse)
端末の種類を判定 userAgent パース / userAgentData.mobile
タッチとマウスを統一ハンドリング Pointer Events(pointerdown 等)
body にデバイスクラスを付与 body.classList.toggle(‘is-mobile’, mql.matches)

ブラウザ判定の詳細は「ブラウザを判定する方法」も併せて参照してください。