タッチUI

スマートフォンやタブレットなどタッチディスプレイに特化したUI要素やライブラリの探求

このページでわかること

  • スワイプ・ピンチ・ドラッグ・ロングプレス・プルトゥリフレッシュの5つのタッチジェスチャー実装パターン
  • @use-gesture/react・Framer Motion・react-swipeable・Pointer Events API による実装比較
  • 判定閾値・物理シミュレーション・iOSの制約など実装時の注意点
  • マウスとタッチの両対応、CSSの touch-action などの実践Tips

タッチUIとは

タッチUIは、スマートフォンやタブレットのタッチディスプレイで使われる、指の動きを入力とするUIインタラクション。マウス操作とは異なり、距離・速度・複数指の同時入力など多次元の情報を扱うため、ライブラリの選定が実装の精度を大きく左右する。

Web では Touch Events、Pointer Events、Gesture Events など複数のイベントAPIが存在し、ブラウザごとの挙動差にも注意が必要。React アプリでは抽象化されたフック(@use-gesture/react など)を使うのが一般的。

本ページでは、React アプリで実装する代表的なタッチジェスチャーを取り上げ、判定アルゴリズムや物理シミュレーションの違いをライブラリ別に比較する。

目的別の選び方

ジェスチャーごとに「判定の難しさ」「物理表現の必要性」が異なる。下表は典型的な選定基準。

ジェスチャー判定難易度物理表現推奨ライブラリ主な用途
スワイプ不要react-swipeable / @use-gestureカルーセル・カード削除
ピンチあれば自然@use-gesture + Framer Motion画像ズーム・地図
ドラッグ必須Framer Motion並べ替え・カード移動
ロングプレス不要@use-gestureコンテキストメニュー
プルトゥリフレッシュ必須@use-gesture + 物理計算リスト更新

実装の落とし穴

タッチUIはブラウザ・OS・端末ごとに挙動差があり、実装時にハマりやすいポイントがいくつかある。

  • iOS Safari の Pull-to-Refresh ネイティブ動作との競合: overscroll-behavior: contain で抑制する
  • スワイプとスクロールの競合: 方向判定の精度が必要。touch-action: pan-y で縦スクロールを許可しつつ横スワイプを取る
  • ピンチ操作時のページズーム抑制: 対象要素に touch-action: none を指定
  • マウスイベントとの併存: Pointer Events API(pointerdown / pointermove / pointerup)で統一すると、touch*mouse* の重複ハンドリングが不要になる

よくある質問

Framer Motion と @use-gesture/react の使い分けは?

Framer Motion は物理アニメーションを含むドラッグ・スワイプの「見た目を動かす」のに強く、@use-gesture/react はジェスチャー検知に特化している。組み合わせて使うことも多く、@use-gesture で検知して Framer Motion で動かす構成がよく採用される。

タッチイベントとマウスイベントの両方に対応するには?

Pointer Events API(pointerdown / pointermove / pointerup)を使うか、それを内部で使うライブラリ(@use-gesture/react など)を採用するのが定石。touch*mouse* を個別に書くと処理が重複しやすい。

スマホでスワイプすると意図せずスクロールしてしまう

CSS の touch-action プロパティで制御する。横スワイプを優先したい場合は touch-action: pan-y、ジェスチャーを完全制御したい場合は touch-action: none を指定する。

ロングプレスのデフォルト時間は何msがいい?

500ms 前後が一般的。@use-gesture では filterTaps: truedelay: 500 で設定する。短すぎるとタップと混同し、長すぎると操作がもたつくため、UI の用途に合わせて調整する。