📱

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

2021/08/15に公開約1,700字

スマホのブラウザでは端からスワイプするとブラウザバックや先のページに進めたりするかと思いますが、アプリの都合上、そうすると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

ログインするとコメントできます