📱

スワイプでのブラウザバックを無効にする

2021/08/15に公開1

スマホのブラウザでは端からスワイプするとブラウザバックや先のページに進めたりするかと思いますが、アプリの都合上、そうするとUXが悪くなる場合があったため、ある条件を満たしたときはスワイプを無効にさせる処理を入れました。

仕様

両端からそれぞれ16pxからスワイプした際にスワイプを無効にさせる。
Reactを使っています。

全体コード

import React, { useEffect, useRef } from 'react'
import { css } from '@emotion/react';

const swipeTitle = css`
  font-size: 20px;
  text-align: center;
`;
const swipeImpossible = css`
  display: flex;
  justify-content: center;
  align-items: center;
  background: cadetblue;
  color: #fff;
  padding: 100px 0;
  font-weight: bold;
  position: relative;
`;

function App() {

  const container = useRef<HTMLDivElement>(null);

  const touchStartEvent = (e) => {
    if (e.touches[0].pageX > 16 && e.touches[0].pageX < window.innerWidth - 16) return;
    e.preventDefault();
  }

  useEffect(() => {
    if (container.current) {
      container.current.addEventListener('touchstart', (e) => touchStartEvent(e));
    }

    return () => {
      if (container.current) {
        container.current.removeEventListener('touchstart', touchStartEvent);
      }
    }
  }, [container.current]);

  return (
    <div>
      <h1 css={swipeTitle}>スワイプキャンセルテスト</h1>
      <div ref={container} css={swipeImpossible}>スワイプ不可ブロック</div>
    </div>
  )
}

export default App

e.preventDefault()でスワイプ制御する

if (e.touches[0].pageX > 16 && e.touches[0].pageX < window.innerWidth - 16) return;
e.preventDefault();

上記の2行が全てなんですが、少し解説すると
touchstartイベントが発火したときに画面両端から16px以内のところを触れていたらe.preventDefault()でtouchstartを制御、それ以外は特に制御はさせません。
またe.pageXではなくe.touches[0].pageXとしているのはandroidでも動作させるためです。

おわり

ただこれをやってもたまにスワイプできてしまうことがあります。
その解決方法は今の所私はわかっていないので、もしスワイプを絶対にさせないような方法をご存じの方がいれば教えていただきたいです。

参考: Blocking Navigation Gestures on iOS Safari

Discussion

toretoretoretore

基本ブラウザ側で制御できないようにしているのでJS側ではそれが限界ですね。。
完全に制御したいのであればネイティブアプリ化を検討するくらいです