スマホだけ操作が効かない:タッチとマウスの違いを見る
遊びをつくる執筆にClaudeを使用しています。

パソコンでは思いどおりに動くのに、スマホで開くとドラッグしても何も起きない、あるいは画面ごと動いてしまう。ブラウザゲームを作る人なら、一度は出会う症状です。コードを何度見直しても、パソコン上で間違いが見つからないのが厄介なところです。 この症状の多くは、ロジックではなく「入力イベントの種類」の食い違いから来ます。マウス用のイベントだけで作ると、スマホでは意図しない順序で呼ばれたり、そもそも呼ばれなかったりします。この記事では、入力イベントの種類を整理し、症状から原因を絞る表と、端末差を埋める最小のコードを示します。最後に、手元の端末で確かめる手順を設計書の形でまとめます。
入力イベントは3系統ある
ブラウザの入力イベントは、大きく3つの系統に分かれます。
- マウスイベント(mousedown、mousemove、mouseup、click など)は、マウスやトラックパッド向けの古くからの仕組みです。
- タッチイベント(touchstart、touchmove、touchend、touchcancel)は、指での操作向けです。複数の指を配列で受け取れます。
- ポインターイベント(pointerdown、pointermove、pointerup、pointercancel)は、マウス・指・ペンを一つの形で扱うための仕組みです。pointerType というプロパティで、"mouse"、"touch"、"pen" のどれかを確かめられます。
スマホで問題が起きやすい理由は、指での操作とマウスの前提が違うからです。違いは主に次の三点です。
- ホバーがありません。 指は画面に触れるまで位置を伝えないので、「カーソルを重ねると表示される」仕掛けは使えません。
- 指の操作にはブラウザの標準動作があります。 指でなぞるとスクロールや拡大縮小が始まるため、ゲーム側がドラッグを受け取る前にブラウザが操作を奪うことがあります。奪われると、pointercancel や touchcancel が届いて操作が途切れます。
- タップのあとに、互換用のマウスイベントが合成されます。 指で触れて離すと、ブラウザは古いサイト向けに mousedown や click などを追って発火させます。touchstart と click の両方に同じ処理を登録すると、一度のタップで二重に反応する原因になります。
「PC でしか確認していない」というのは、この3点を一度も通っていない状態です。
症状から原因を絞る
起きていることから、疑う場所を決めてしまいましょう。次の表は、よくある症状と、最初に確かめる箇所の対応です。
- ドラッグを始めるとページがスクロールし、操作が途中で止まる、まず疑う箇所:要素に touch-action が指定されていません、確かめ方:ドラッグ中に pointercancel が届くか、ログに出して見ます
- 一回のタップで二回反応する、まず疑う箇所:touchstart と click など、複数系統に同じ処理を登録しています、確かめ方:各ハンドラーの先頭でイベント名を出力します
- 押した位置と反応する位置がずれる、まず疑う箇所:canvas の内部サイズと、画面上の表示サイズが違います、確かめ方:座標を表示サイズ比で換算しているか見ます
- 指がキャンバスの外に出ると操作が切れる、まず疑う箇所:ポインターキャプチャを使っていません、確かめ方:pointerup が要素外で失われていないか確かめます
- 重ねると出る説明や操作がスマホで使えない、まず疑う箇所:ホバーに依存しています、確かめ方:タップだけで同じ情報に届くか確かめます
- 矢印キーでしか動かせない、まず疑う箇所:画面上の操作手段がありません、確かめ方:キーボードなしの端末で一通り遊べるか確かめます
- PC では効くキー操作が、開いた直後は効かない、まず疑う箇所:入力先のフォーカスがゲーム画面にありません、確かめ方:一度画面をクリックしてから試します
- スマホで音だけ鳴らない、まず疑う箇所:音は、ユーザー操作のあとでないと再生できない場合があります、確かめ方:最初のタップ後に音を初期化しているか見ます
最後の2行は入力そのものの問題ではありません。ただ、「スマホだけ反応しない」という訴えの中に混ざりやすいので、切り分けの対象に入れています。キー入力のフォーカスについては、アソバースのようにゲームを埋め込み枠(iframe)で動かす環境で、枠のどの動作がどう影響するかは確認済みの情報にありません。その部分は、実際に作品を開いて確かめてください。
端末差を埋める最小のコード
方針は単純で、入力の窓口をポインターイベントに一本化し、スクロール対策と座標換算を入れることです。次は、キャンバスをなぞると点が描かれる、単独で動く最小の例です。HTMLファイルとして保存して開けば動きます。
<canvas id="c" width="320" height="200"
style="touch-action:none;border:1px solid #888;max-width:100%"></canvas>
<p id="log">キャンバスをなぞってください</p>
<script>
const c = document.getElementById('c');
const ctx = c.getContext('2d');
const log = document.getElementById('log');
let dragging = false;
function pos(e) {
const r = c.getBoundingClientRect();
return {
x: (e.clientX - r.left) * c.width / r.width,
y: (e.clientY - r.top) * c.height / r.height
};
}
function draw(e) {
const p = pos(e);
ctx.fillRect(p.x - 2, p.y - 2, 4, 4);
log.textContent = e.type + '(' + e.pointerType + ')';
}
function end(e) {
dragging = false;
log.textContent = e.type + '(' + e.pointerType + ')';
}
c.addEventListener('pointerdown', e => {
dragging = true;
c.setPointerCapture(e.pointerId);
draw(e);
});
c.addEventListener('pointermove', e => { if (dragging) draw(e); });
c.addEventListener('pointerup', end);
c.addEventListener('pointercancel', end);
</script>読みどころは3か所あります。
- touch-action:none は、この要素の上では指によるスクロールや拡大をブラウザに任せない、という宣言です。これがないと、ドラッグの途中でブラウザが操作を引き取り、pointercancel が届きます。ページ全体を固定したくない場合は、pan-y のように許可する動きを残す書き方も選べます。
- setPointerCapture は、指やカーソルが要素の外へ出ても、その操作のイベントを同じ要素に届け続けます。ドラッグ中に指が外れても pointerup を受け取れます。
- pos 関数 は、画面上の表示サイズと内部の描画サイズの比で座標を換算します。CSSで max-width:100% を掛けて縮めた場合でも、位置がずれません。表示サイズは、画面の回転や拡大で変わることがあるため、イベントのたびに測り直すのが安全です。
なお、pointercancel を pointerup と同じ終了処理に結びつけているのは、押しっぱなしの状態が残るのを防ぐためです。
公式作品の操作から読み取れること
アソバースの公式作品のうち、確認済みの情報から入力の設計を読み取れるものがあります。内部の実装方法は確認済みの情報に含まれないため、ここでは「操作手段が複数用意されている」という点に絞ります。
- 紙ひこうき郵便は、左右キー、ドラッグ、矢印ボタンの3つで操縦できます。キーボードのある環境、指やマウスでなぞる環境、キーを持たない環境のそれぞれに入口があると読めます。
- 潮目のオセロは、矢印キーとEnterでも操作できます。盤面を直接押す以外の経路があり、入力手段が限られた状況に配慮した設計と読み取れます。
- 雨音のピアノは、キーボード側にA W S E D F T G Y H U J、音域にZ/Xの割り当てがあります。画面上の鍵盤をどう操作できるかは、作品を開いて確かめてください。
- 小さな軌道とプリズムの道は、角度や初速の決定、鏡の切り替えが要点です。どの入力でどう決めるかの細部は、作品を開いて確かめてください。
共通の設計として、プレイ画面を拡大しても進行が保たれる点も確認済みです。画面サイズが途中で変わりうるということなので、自作でも座標を固定値で持たず、表示サイズから毎回求める考え方が向いています。
ここから言えるのは、一つの入力方法に賭けない、という方針です。キーボード専用の操作を作ったら、画面上のボタンを足す。ドラッグ操作を作ったら、キーでも動かせる道を残す。それが端末差を埋める現実的な手段です。
自分の端末で確かめる設計書
ここからは、読者が自分で行う確認の手順です。結果はこの記事では示しません。手元の端末で出た記録が、そのまま答えになります。
問い:自作ゲームの各操作は、パソコンのマウス、スマホの指、キーボードのそれぞれで成立するか。
準備するもの
- パソコンのブラウザと、手元のスマホまたはタブレット(できれば2種類)
- 画面にイベント名を表示する簡易ログ(上のコードの log 部分が使えます)
- 確認する操作の一覧(開始・選択・ドラッグ・決定・一時停止など)
手順
- 操作を1つずつ書き出し、「マウス/指/キーボード」の3列の表を作ります。
- 各操作を各手段で行い、期待どおり動けば○、動かなければ×、二重に反応すれば△と記録します。
- ×と△の行は、ログの pointerType とイベント名を一緒にメモします。
- 各操作は、同じ端末で3回ずつ試します。1回だけ失敗した場合は、タイミングの問題かどうかを切り分けるためです。
- 画面を縦から横へ回転させたり、プレイ画面を拡大したりした状態でも、座標の操作をもう一度試します。
結果の読み方
- 指でだけ×で、ログに pointercancel が出ているなら、touch-action を最初に疑います。
- 指でだけ△なら、複数系統のイベントに同じ処理を登録していないか見ます。
- 回転や拡大の後にだけ位置がずれるなら、座標の換算を毎回やり直しているか確かめます。
- キーボードの列だけ×なら、画面を一度クリックしてフォーカスを与えた後に試し直します。
起こりやすい誤り
- パソコンのブラウザの端末エミュレーション機能は便利ですが、実機のスクロールや拡大の挙動を完全には再現しません。最終確認は実機で行ってください。
- 一種類の端末だけで○になっても、他の端末で同じとは限りません。画面サイズや OS が違う端末を、できれば2種類以上使います。
アソバースに投稿する場合は、「入力→表示の確認→公開」の3段階の途中にある表示の確認で、この表を使って一通り試せます。
次の行動
まず、自作ゲームの操作を一覧にして、マウス・指・キーボードの3列の表を作ってください。つぎに、×や△が付いた行を、上の症状表に当てはめて原因を絞り、入力の窓口をポインターイベントへまとめる修正から始めます。そのうえで、紙ひこうき郵便や潮目のオセロを開き、複数の入力手段がどう用意されているかを、自分の端末で触って確かめてみてください。
参考資料
- MDN Web Docs「Pointer events」
- MDN Web Docs「Touch events」
- MDN Web Docs「touch-action」
- W3C「Pointer Events」仕様

