サイトにタッチを追加する

スマートフォンからデスクトップ画面に至るまで、タッチスクリーンはますます多くのデバイスで利用できます。アプリは、直感的かつ美しい方法でタップに反応する必要があります。

タッチスクリーンは、スマートフォンから あります。ユーザーが UI を操作することを選択すると、アプリは 直感的な方法でタップに反応します

要素の状態に対応する

ウェブページ上の要素をタップまたはクリックしたことで、 サイトが実際にそれを検知したのか?

ユーザーによるパーツのタップや操作に応じて要素の色が変わる ウェブサイトが機能していることが基本的な安心感を与えてくれます。Google は、 ストレスが軽減され、テンポよくレスポンシブな印象になります。

DOM 要素は、デフォルト、フォーカス、ホバーの状態を継承できます。 定義できます。これらの状態ごとに UI を変更するには、スタイルを適用する必要があります。 以下に示すように、疑似クラス :hover:focus:active に追加します。

.btn {
  background-color: #4285f4;
}

.btn:hover {
  background-color: #296cdb;
}

.btn:focus {
  background-color: #0f52c1;

  /* The outline parameter suppresses the border
  color / outline when focused */
  outline: 0;
}

.btn:active {
  background-color: #0039a8;
}

試してみる

ボタンのさまざまな色を示す画像
州

ほとんどのモバイル ブラウザでは、要素にマウスオーバーフォーカスの状態が適用されます。 メッセージを表示できます。

設定するスタイルとそのスタイルがユーザーにどのように見えるかを慎重に検討する 顧客満足度の向上につながります

デフォルトのブラウザ スタイルを抑制する

さまざまな状態用のスタイルを追加すると、ほとんどのブラウザでは ユーザーのタップ操作に応じて独自のスタイルを実装します。これは主に モバイルデバイスが発売された当初は :active 状態のスタイル設定が必要です。その結果、多くのブラウザが ユーザーにフィードバックを提供します。

ほとんどのブラウザでは、outline CSS プロパティを使用して、 要素にフォーカスが移ったときに通知を受け取れます。これを非表示にするには、次のコマンドを使用します。

.btn:focus {
    outline: 0;

    /* Add replacement focus styling here (i.e. border) */
}

Safari と Chrome でタップのハイライト表示の色が追加されている -webkit-tap-highlight-color CSS プロパティ:

/* Webkit / Chrome Specific CSS to remove tap
highlight color */
.btn {
  -webkit-tap-highlight-color: transparent;
}

試してみる

Windows Phone の Internet Explorer でも、動作は似ていますが、動作は抑制されています。 メタタグを使用:

<meta name="msapplication-tap-highlight" content="no">

Firefox では 2 つの副作用を処理する必要があります。

-moz-focus-inner 疑似クラス。アウトラインを追加する タップ可能な要素がある場合は、border: 0 を設定することで削除できます。

Firefox で <button> 要素を使用している場合、グラデーションが表示されます。 適用されています。これは、background-image: none を設定することで削除できます。

/* Firefox Specific CSS to remove button
differences and focus ring */
.btn {
  background-image: none;
}

.btn::-moz-focus-inner {
  border: 0;
}

試してみる

ユーザー選択を無効にする

UI を作成する際は、ユーザー エクスペリエンスの 操作できるものの、デフォルトの動作を抑制したい場合は、 UI 上でマウスをドラッグして 長押ししてテキストを選択するか

これは user-select CSS プロパティで行うことができますが、 コンテンツでこれを行うことは非常に不快感を与える可能性があります。 要素の中のテキストを選択する場合に、自動的に選択されるようになります。 そのため、慎重に慎重に使用してください。

/* Example: Disable selecting text on a paragraph element: */
p.disable-text-selection {
  user-select: none;
}

カスタム ジェスチャーを実装する

サイトで使用するカスタムのインタラクションやジェスチャーについて 次の 2 つのトピックに留意してください

  1. すべてのブラウザをサポートする方法。
  2. フレームレートを高く保つ方法

この記事では、これらのトピックについて取り上げ、必要な API に関する すべてのブラウザへのヒットをサポートし これらのイベントの使い方を説明します 支援します

ジェスチャーで行う動作に応じて、 ユーザーに一度に 1 つの要素の操作を許可するか、または 複数の要素を同時に操作できます

この記事では、2 つの例を紹介します。いずれも、 高フレームレートを維持する方法を紹介します

ドキュメントのタッチ操作の GIF の例

最初の例では、ユーザーが 1 つの要素を操作できるようにします。この 1 つの要素にすべてのタッチイベントを渡すようにすることもできます。ただし、 要素自体で最初に開始された操作として認識されます。たとえば、 スワイプ可能な要素から指を離しても、要素をコントロールできます。

ユーザーに高い柔軟性をもたらすため便利ですが、 ユーザーが UI を操作する方法を制限します。

要素のタップの GIF の例

ただし、ユーザーが複数の要素を同時に操作することが予想される場合は、 時間(マルチタッチを使用)では、タップを特定の 要素です。

これはユーザーにとってはより柔軟性がありますが、情報を操作するロジックが複雑になります。 ユーザーエラーに対する耐障害性が低下します

イベント リスナーを追加する

Chrome(バージョン 55 以降)、Internet Explorer、Edge、 カスタム ジェスチャーの実装に推奨されるアプローチは、PointerEvents です。

他のブラウザでは、TouchEventsMouseEvents が適切な方法です。

PointerEvents の優れた点は、複数のタイプの入力を結合できることです。 マウス、タッチ、ペンの各イベントをまとめて 1 つの 使用します。リッスンするイベントは、pointerdownpointermovepointeruppointercancel

他のブラウザでの同等の機能は、touchstarttouchmove、 タッチイベント用の touchendtouchcancel。 マウス入力に対して、mousedown を実装する必要があるのと同じ操作です。 mousemovemouseup

使用するイベントについてご不明な点がある場合は、 タップイベント、マウスイベント、ポインタ イベント

これらのイベントを使用するには、DOM で addEventListener() メソッドを呼び出す必要があります。 要素、イベントの名前、コールバック関数、ブール値です。 このブール値は、イベントをその前後にキャッチすべきかどうかを決定します 他の要素によって、他の要素を捕捉して解釈する機会が できます。(true は、他の要素よりもイベントを優先することを意味します)。

次に、インタラクションの開始をリッスンする例を示します。

// Check if pointer events are supported.
if (window.PointerEvent) {
  // Add Pointer Event Listener
  swipeFrontElement.addEventListener('pointerdown', this.handleGestureStart, true);
  swipeFrontElement.addEventListener('pointermove', this.handleGestureMove, true);
  swipeFrontElement.addEventListener('pointerup', this.handleGestureEnd, true);
  swipeFrontElement.addEventListener('pointercancel', this.handleGestureEnd, true);
} else {
  // Add Touch Listener
  swipeFrontElement.addEventListener('touchstart', this.handleGestureStart, true);
  swipeFrontElement.addEventListener('touchmove', this.handleGestureMove, true);
  swipeFrontElement.addEventListener('touchend', this.handleGestureEnd, true);
  swipeFrontElement.addEventListener('touchcancel', this.handleGestureEnd, true);

  // Add Mouse Listener
  swipeFrontElement.addEventListener('mousedown', this.handleGestureStart, true);
}

試してみる

単一要素のインタラクションを処理する

上記の短いコード スニペットでは、開始イベント リスナーのみを追加しています。 使用できます。これは、マウスイベントによって イベント リスナーが追加されている要素の上にカーソルが移動したとき。

TouchEvents は、場所にかかわらず、開始後に操作をトラッキングします タップが発生し、PointerEvents が接触位置に関係なくイベントをトラッキングします。 DOM 要素で setPointerCapture が呼び出された後に行われます。

マウスの移動イベントと終了イベントについては、 リスナーをドキュメントに追加すると、 完了するまでカーソルをトラックし続けます。

実装の手順は以下のとおりです。

  1. すべての TouchEvent リスナーと PointerEvent リスナーを追加。MouseEvent はのみを追加します トリガーされます。
  2. 開始操作コールバック内で、マウスの移動イベントと終了イベントを 表示されます。この方法では、可否に関係なくすべてのマウスイベントが 元の要素でイベントが発生するかどうか。PointerEvent については、 元の要素で setPointerCapture() を呼び出す必要があります。 すべてのイベントを記録します。次に、操作の開始を処理します。
  3. 移動イベントを処理します。
  4. 終了イベントで、マウス移動リスナーと終了リスナーをドキュメントから削除する 操作を終了します。

以下は、移動を追加する handleGestureStart() メソッドのスニペットです。 end イベントをドキュメントに追加します。

// Handle the start of gestures
this.handleGestureStart = function(evt) {
  evt.preventDefault();

  if(evt.touches && evt.touches.length > 1) {
    return;
  }

  // Add the move and end listeners
  if (window.PointerEvent) {
    evt.target.setPointerCapture(evt.pointerId);
  } else {
    // Add Mouse Listeners
    document.addEventListener('mousemove', this.handleGestureMove, true);
    document.addEventListener('mouseup', this.handleGestureEnd, true);
  }

  initialTouchPos = getGesturePointFromEvent(evt);

  swipeFrontElement.style.transition = 'initial';
}.bind(this);

試してみる

追加する終了コールバックは handleGestureEnd() で、これにより移動が削除されます。 end イベント リスナーをドキュメントから送り、ポインタのキャプチャを解放して、 呼び出すことができます。

// Handle end gestures
this.handleGestureEnd = function(evt) {
  evt.preventDefault();

  if (evt.touches && evt.touches.length > 0) {
    return;
  }

  rafPending = false;

  // Remove Event Listeners
  if (window.PointerEvent) {
    evt.target.releasePointerCapture(evt.pointerId);
  } else {
    // Remove Mouse Listeners
    document.removeEventListener('mousemove', this.handleGestureMove, true);
    document.removeEventListener('mouseup', this.handleGestureEnd, true);
  }

  updateSwipeRestPosition();

  initialTouchPos = null;
}.bind(this);

試してみる

このパターンに従ってドキュメントに移動イベントを追加すると、 ユーザーが要素の操作を開始し、そのジェスチャーを要素の外側に 要素がある場合、場所を問わずにマウスの動きを継続的に受け取ります。 イベントはドキュメントから受信されているため、ページ上にあります。

この図は、 移動や終了のイベントをドキュメントに移動できます。

タッチイベントをドキュメントにバインドする
`touchstart`

タップに効率的に応答する

開始イベントと終了イベントの処理が完了したので、 応答します。

開始イベントと移動イベントのいずれについても、xy を簡単に抽出できます。 便利です。

次の例では、イベントが TouchEvent からのものかどうかを確認します。 targetTouches が存在するかどうかを確認しています。存在する場合は 最初の接触から clientXclientY。 イベントが PointerEvent または MouseEvent の場合は、clientX を抽出し、 イベント自体から直接 clientY を取得します。

function getGesturePointFromEvent(evt) {
    var point = {};

    if (evt.targetTouches) {
      // Prefer Touch Events
      point.x = evt.targetTouches[0].clientX;
      point.y = evt.targetTouches[0].clientY;
    } else {
      // Either Mouse event or Pointer Event
      point.x = evt.clientX;
      point.y = evt.clientY;
    }

    return point;
  }

試してみる

TouchEvent には、タッチデータを含む 3 つのリストがあります。

  • touches: 画面上で現在行われているすべてのタップのリスト(指定の有無は問わない) 対象の DOM 要素。
  • targetTouches: イベントによって現在発生している DOM 要素上のタップのリスト あります。
  • changedTouches: イベントにつながった変更のタップのリスト 発生します。

ほとんどの場合、targetTouches には必要なものがすべて揃っています。( これらのリストについて詳しくは、タップリストをご覧ください)。

requestAnimationFrame を使用する

イベント コールバックはメインスレッドで呼び出されるため、次のように実行します。 イベントのコールバックにコードをできるだけ少なくして、 ジャンクを防止できます

requestAnimationFrame() を使用すると、UI を更新することができます。 ブラウザがフレームを描画する前に表示されるようになり、 イベントコールバックで処理します

requestAnimationFrame() をまだよくご存じない場合は、 こちらで詳細をご覧ください。

一般的な実装では、x 座標と y 座標を 開始イベントと移動イベント、移動イベント内のアニメーション フレームのリクエスト 呼び出すことができます。

このデモでは、最初の接触位置を handleGestureStart() に保存します(initialTouchPos を探してください)。

// Handle the start of gestures
this.handleGestureStart = function(evt) {
  evt.preventDefault();

  if (evt.touches && evt.touches.length > 1) {
    return;
  }

  // Add the move and end listeners
  if (window.PointerEvent) {
    evt.target.setPointerCapture(evt.pointerId);
  } else {
    // Add Mouse Listeners
    document.addEventListener('mousemove', this.handleGestureMove, true);
    document.addEventListener('mouseup', this.handleGestureEnd, true);
  }

  initialTouchPos = getGesturePointFromEvent(evt);

  swipeFrontElement.style.transition = 'initial';
}.bind(this);

handleGestureMove() メソッドはイベントの位置を保存します。 リクエストの前に、必要に応じてアニメーション フレームを onAnimFrame() 関数をコールバックとして使用します。

this.handleGestureMove = function (evt) {
  evt.preventDefault();

  if (!initialTouchPos) {
    return;
  }

  lastTouchPos = getGesturePointFromEvent(evt);

  if (rafPending) {
    return;
  }

  rafPending = true;

  window.requestAnimFrame(onAnimFrame);
}.bind(this);

onAnimFrame 値は、呼び出されると UI を変更する関数です。 移動しますこの関数を requestAnimationFrame() に渡すと、 ページを更新する直前にこの関数を呼び出すようブラウザに指示します (ページの変更内容を描画するなど)。

handleGestureMove() コールバックでは、最初に rafPending が false かどうかを確認します。 onAnimFrame()requestAnimationFrame() によって呼び出されたかどうかを示します。 直近の移動イベント以降ですつまり、requestAnimationFrame() は 1 つだけです。 常に待機している状態です

onAnimFrame() コールバックが実行されると、任意のイベントに変換が設定されます。 rafPendingfalse に更新する前に移動する要素を指定して、 新しいアニメーション フレームがリクエストされます。

function onAnimFrame() {
  if (!rafPending) {
    return;
  }

  var differenceInX = initialTouchPos.x - lastTouchPos.x;
  var newXTransform = (currentXPosition - differenceInX)+'px';
  var transformStyle = 'translateX('+newXTransform+')';

  swipeFrontElement.style.webkitTransform = transformStyle;
  swipeFrontElement.style.MozTransform = transformStyle;
  swipeFrontElement.style.msTransform = transformStyle;
  swipeFrontElement.style.transform = transformStyle;

  rafPending = false;
}

タップ操作でジェスチャーを制御する

CSS プロパティ touch-action を使用すると、デフォルトのタップを制御できます。 制御できます。この例では、touch-action: none を使用して以下を行います。 ブラウザがユーザーの操作を一切行えないようにし、タップすることで、 すべてのタッチイベントをインターセプトします

/* Pass all touches to javascript: */
button.custom-touch-logic {
  touch-action: none;
}

touch-action: none を使用すると、すべての脅威を防ぐことができるため、核となるオプションである 変更できます。多くの場合、いずれかの方法は 以下の方法が適しています。

touch-action を使用すると、ブラウザで実装された操作を無効にできます。 たとえば、IE10 以降ではダブルタップによるズーム操作がサポートされています。ルールの manipulation 件中 touch-action 件、デフォルトのダブルタップを無効にしています 確認します。

これにより、ダブルタップ ジェスチャーを自分で実装できます。

よく使用される touch-action 値は次のとおりです。

タップ操作パラメータ
touch-action: none タップ操作は アクセスできます。
touch-action: pinch-zoom 次のブラウザ操作がすべて無効になります。 `touch-action: none` と `ピンチズーム` は除く(引き続き アクセスできます。
touch-action: pan-y pinch-zoom JavaScript で水平スクロールを処理する 縦方向のスクロールやピンチズーム(画像カルーセルなど)を無効にする。
touch-action: manipulation ダブルタップ操作が無効になり、 ブラウザによるクリックの遅延スクロールせずに、ピンチズームで できます。

古いバージョンの IE のサポート

IE10 をサポートする場合、 PointerEvents

PointerEvents がサポートされているかどうかを確認するには、通常 window.PointerEvent ですが、IE10 では、 window.navigator.msPointerEnabled

ベンダー プレフィックス付きのイベント名は、'MSPointerDown''MSPointerUp'、および 'MSPointerMove'

下の例は、サポートの有無を確認して切り替える方法を示しています イベント名を定義します。

var pointerDownName = 'pointerdown';
var pointerUpName = 'pointerup';
var pointerMoveName = 'pointermove';

if (window.navigator.msPointerEnabled) {
  pointerDownName = 'MSPointerDown';
  pointerUpName = 'MSPointerUp';
  pointerMoveName = 'MSPointerMove';
}

// Simple way to check if some form of pointerevents is enabled or not
window.PointerEventsSupport = false;
if (window.PointerEvent || window.navigator.msPointerEnabled) {
  window.PointerEventsSupport = true;
}

詳しくは、 Microsoft

リファレンス

タッチ状態の疑似クラス

クラス 説明
:カーソル
押された状態のボタン
要素にカーソルを合わせると表示されます。 カーソルを合わせると UI が変化し、ユーザーによる操作が促進される 要素で表します。
:Focus
フォーカス状態のボタン
ユーザーがページ上の要素をタブで移動すると入力されます。フォーカス状態 現在操作している要素をユーザーが把握できる 次を含む:を使用すると、ユーザーがキーボードを使用して UI を簡単に操作できるようになります。
アクティブ
押された状態のボタン
要素の選択時に入力。 たとえばユーザーが要素をクリックまたはタップしたときなどです

確定的なタッチイベント リファレンスはこちらをご覧ください。 W3C タッチイベント

タッチイベント、マウスイベント、ポインタ イベント

これらのイベントは、新しい操作を アプリケーション:

タップ、マウス、ポインタ イベント
touchstart, mousedown, pointerdown 指が最初に要素に接触したとき、または ユーザーがマウスをクリックするだけです
touchmove, mousemove, pointermove ユーザーが画面上で指を動かすか、 マウスでドラッグします。
touchend, mouseup, pointerup ユーザーが画面から指を離すと呼び出されます。 マウスを離すこともできます
touchcancel pointercancel ブラウザがタッチ操作をキャンセルすると呼び出されます。たとえば ユーザーがウェブアプリをタップしてからタブを切り替えた場合です。

タッチリスト

各タッチイベントには、次の 3 つのリスト属性が含まれます。

タッチイベントの属性
touches 要素に関係なく、現在画面上のすべてのタップのリスト できます。
targetTouches ターゲットとなる要素で開始したタッチのリスト クリックします。たとえば、<button> にバインドする場合、 現在そのボタンのタップのみが 表示されますPod を そのドキュメントに対するすべての連絡先が表示されます。
changedTouches イベント発生の原因となった変化した接触のリスト: <ph type="x-smartling-placeholder">
    </ph>
  • touchstart イベントでアクティブになったばかりの タッチポイントのリストです 選択します。
  • touchmove event-- 直近の位置から移動したタッチポイントのリスト イベントです。
  • touchend および touchcancel イベント -- 削除されたばかりのタッチポイントのリスト 実現できるのです

iOS でアクティブ状態のサポートを有効にする

残念ながら、iOS の Safari はデフォルトでは「アクティブ」状態を適用せず、 動作させるには、touchstart イベント リスナーをドキュメントに追加する必要があります。 body または各要素に対して指定できます。

これは、iOS デバイスでのみ実行されるように、ユーザー エージェント テストの背後で行う必要があります。

ボディにタッチ開始を追加すると、すべての要素に適用できるというメリットがあります。 ただし、ページをスクロールするときにパフォーマンスの問題が発生する可能性があります。

window.onload = function() {
  if (/iP(hone|ad)/.test(window.navigator.userAgent)) {
    document.body.addEventListener('touchstart', function() {}, false);
  }
};

または、タップ開始リスナーをすべての操作可能な パフォーマンス上の懸念が軽減されます。

window.onload = function() {
  if (/iP(hone|ad)/.test(window.navigator.userAgent)) {
    var elements = document.querySelectorAll('button');
    var emptyFunction = function() {};

    for (var i = 0; i < elements.length; i++) {
        elements[i].addEventListener('touchstart', emptyFunction, false);
    }
  }
};