スマホではハンバーガーメニュー、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.mobilematchMedia で画面幅で判定する(推奨)
// CSS のブレークポイント(768px)で判定
const isMobile = window.matchMedia("(max-width: 768px)").matches;
if (isMobile) {
console.log("モバイル表示");
initHamburgerMenu();
} else {
console.log("PC 表示");
initDropdownMenu();
}
// ウィンドウリサイズ時にも判定を更新(レスポンシブ対応)
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);
・CSS のブレークポイントと同じ基準で判定できる(768px / 1024px 等を統一)
・
addEventListener("change") でリサイズに自動追従・ブラウザに依存しない(userAgent のパースが不要)
・タブレットの扱いもブレークポイントで自然に解決
userAgent で端末種別を判定する
// スマートフォンの判定(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 以降の Safari は
Macintosh として報告され、iPad が userAgent に含まれません。navigator.maxTouchPoints > 1 との組み合わせで判定してください。maxTouchPoints でタッチ対応を判定する
// タッチデバイスかどうか
function isTouchDevice() {
return navigator.maxTouchPoints > 0
|| "ontouchstart" in window;
}
if (isTouchDevice()) {
// タッチ操作用の処理
enableSwipeNavigation();
} else {
// マウス操作用の処理
enableHoverEffects();
}
Surface、タッチ対応ノート PC など、マウスとタッチの両方に対応するデバイスが増えています。
isTouchDevice() が true でも「スマホ」とは限りません。タッチ判定は「タッチ操作を有効にするか」の判断に使い、レイアウトの切り替えには matchMedia を使ってください。userAgentData.mobile(Chromium 系限定)
// 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);
}
ブラウザ判定の詳細は「ブラウザを判定する方法」を参照してください。
統合的なデバイス判定関数
// 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 メディアクエリだけで対応できます。
/* 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) | 精密なポインター(マウス / トラックパッド) |
JavaScript でタッチ判定する代わりに、CSS の
@media (hover: hover) でホバー効果を出し分けたり、@media (pointer: coarse) でタップ領域を大きくしたりできます。表示の出し分けだけならCSS だけで完結させるのが最もシンプルです。実務パターン集
パターン(1): スマホ用ハンバーガーメニュー / PC 用ナビバー
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 でドラッグ
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);
pointerdown / pointermove / pointerup はタッチとマウスの両方に対応するイベントです。タッチとマウスを個別にハンドリングする必要がなくなるため、新規開発では Pointer Events を推奨します。パターン(3): PC のみホバーでツールチップ表示
// ホバーが使えるデバイスのみツールチップを有効化
if (window.matchMedia("(hover: hover)").matches) {
document.querySelectorAll("[data-tooltip]").forEach(el => {
el.addEventListener("mouseenter", showTooltip);
el.addEventListener("mouseleave", hideTooltip);
});
}
パターン(4): スマホで遅延読み込みの閾値を変更
// スマホは通信量を節約するため早めに遅延読み込み
const rootMargin = window.matchMedia("(max-width: 768px)").matches
? "200px" // スマホ: 200px 手前で読み込み
: "500px"; // PC: 500px 手前で読み込み
const observer = new IntersectionObserver(callback, { rootMargin });
パターン(5): body にデバイスクラスを付与
// ページ読み込み時にデバイスクラスを付与
// 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; }
よくある質問
matchMedia が最適です。CSS のブレークポイントと統一でき、リサイズにも追従します。端末の物理的な種類(iPhone なのか Android なのか)を知りたい場合は userAgent を使います。(min-width: 769px) and (max-width: 1024px) でタブレット帯を定義できます。@media (hover: hover) で対応。イベントハンドラの切り替え(スワイプ / ドラッグの登録)は JavaScript の maxTouchPoints で対応。表示の出し分けだけなら CSS で完結させるのが最もシンプルです。まとめ
デバイス判定と処理の切り替えの要点をまとめます。
| やりたいこと | 推奨方法 |
|---|---|
| 画面幅でレイアウトを切り替え | 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) |
ブラウザ判定の詳細は「ブラウザを判定する方法」も併せて参照してください。

