とある要素に「position: fixed」をかけて、そいつにタッチイベントで何か処理をすることってたまにあるかと思います。
例えば上下左右にメニューバーみたいなのが固定で表示してあって、それをスワイプで閉じたり開いたりできるようなものなど。
先日似たようなものを実装した際に、iOS Safariでのみとあるバグで躓いたことがあったので共有します。
ページ全体のスクロール直後にタッチイベントが発生しなくなるときがある?
バグがあるデモ(※iOS Safariで確認してください)
まずはバグのある状態のデモを用意しました。
グレーの四角いボックスがタッチで動くようになっています。
(インタラクティブなサイトとかだとこういう機能もたまに見かけますよね笑)
一見特に何も問題ないように見えますが、ページ全体を何度かスクロールした後にボックスをタッチで移動しようとすると……
稀にボックスが動かずページ全体がスクロールしてしまうことがあります。
稀になので気にならない場合もあるかもしれませんが、デザインや機能によってはめちゃくちゃストレスになることもあります。
ということで改善方法を検証してみました。
親要素にタッチイベントをセットすると何故か解消される
結論から言うと見出しの通り、親要素に中身が空でも良いので、タッチイベントをセットするというだけで解消されました!(超謎仕様!w)
こちらがそのデモになります。
修正済みのデモ(※iOS Safariで確認してください)
デモの中では下記のような処理を追加しています。
document.getElementById('container').addEventListener('touchstart', (e) => { // 何もしない }); document.getElementById('container').addEventListener('touchmove', (e) => { // 何もしない });
本当に中身は何もありませんw
しかしこれを入れるだけで、スクロール後にタッチイベントが発生しなくなることがなくなりました!
考察
これ原因が全く分からないんですよね……
なのでここからはあくまで考察程度にはなりますが、
そもそもiOS Safariでスクロールすると、慣性スクロールで指を離した直後も少しの間だけスクロールが続きます。
このときにボックスを動かそうとしても、スクロールの方が優先されます。
仮にこの状態を裏でスクロールモードのようなフラグがあると仮定して、本来はスクロールが終わったタイミングでそのフラグがOFFになるはずが、稀にスクロールが終わってもこのフラグがOFFにならないままスクロール中扱いになることがあるのではないかと考えてみました。
つまり、スクロールが終わってもブラウザ側ではまだスクロール中扱いのため、ボックスのタッチイベントよりページ全体のスクロールが優先されてしまう、ということ。
ただし、だとしても親要素にタッチイベントをセットするだけで解消される理由はよく分かりませんw
おそらくページ全体のスクロール直後にタッチしたときに、親要素のタッチイベントが発火することで、スクロールではない扱いになるということなんでしょうか?(自分で言っていてもよく分かりませんw)
もしこのへん詳しい方いたら教えていただけるとありがたいです!
コメント