iOS Safari でダブルタップによるズームを防ぐには touch-action: manipulation が一番簡単
iOS Safari で見せる Web サイトをネイティブアプリ風に見せるための演出の一つとして、適当なところでダブルタップした時にズームしないことを実現したい。
Twitter や Instagram を iOS Safari で見るとそのような動きが実現されているので、何かやり方はあるんだろうなぁーと思ったのだけど、かなり手こずってしまった。
目次
- iOS10 までは
user-scalable=no
が使えた - JavaScript で TouchEnd イベントをチェックする方法
touch-action: manipulation
が一番カンタン
iOS10 までは user-scalable=no
が使えた
meta
要素で指定するヤツ。今では動かない。
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
どうも iOS10 以降で、ユーザビリティを考えてズームを禁止させない方針になったため、user-scalable=no
指定は無効になった。
JavaScript で TouchEnd イベントをチェックする方法
こんなコード。
let lastTouchEndTime = 0;
document.addEventListener('touchend', (event) => {
const now = new Date().getTime();
if((now - lastTouchEndTime) < 350) {
event.preventDefault();
}
lastTouchEndTime = now;
});
要するに「350ミリ秒以内の2回目のタップを無効化する」という処理なのだが、試していた限りどうやってもこの処理をすり抜けてしまうタイミングがあった。400ミリ秒とか700ミリ秒とか色々試したが、あまりしきい値を大きくしすぎると、今度は少し素早い操作をしていて「別々の2タップ」のつもりだったのに、後のタップ操作が無効化されてしまったりと、綺麗にいかなかった。
- 参考 : iPhoneのSafariでページを拡大縮小させない方法
- 参考 : iPhoneのSafariでダブルタップを無効にする(iOS10でもどうしてもuser-scalable=noを有効にしたい場合とか) - みかづきブログ その3
ちなみに、ピンチ操作を無視する JavaScript もある。
document.addEventListener('touchstart', (event) => {
if(event.touches && event.touches.length > 1) {
event.preventDefault();
}
}, {
passive: false
});
2本指以上のタップを無効化している。iOS11 あたりから passive: false
指定がないと上手く効かなくなった。
他にも、TouchEnd
時のイベントで preventDefault()
しつつ、click()
を呼んでやる、というようなハックも見かけたが、さすがにイマイチか。
なお、ズーム倍率は event.scale
の値で確認できる。1
を等倍 (100%) として表現されるが、ReadOnly なプロパティなので、event.scale = 1
などと代入しても、倍率をリセットすることはできなかった。
この辺のスクリプトで試行錯誤したが、綺麗に実現できるモノがなかった。
touch-action: manipulation
が一番カンタン
CSS で touch-action
というプロパティがある。スワイプ操作に制限を与えるプロパティだ。
しかし Can I Use を見たところ、iOS Safari では auto
と manipulation
しか許容していないようだった。
touch-action
で検索すると以下の日本語文献がよくヒットするのだが、イマイチ文脈が分からないので無視した。プロパティの説明としては合ってる。
で、初期値である auto
を除いて、iOS Safari で唯一使える touch-action: manipulation
というプロパティを調べてみたところ、
- 2本指でのピンチ操作によるズームは制限しない
- ダブルタップによるズームは抑止する
という仕様のようだ。
ということで、JavaScript は使わず、以下のコードだけでダブルタップによるズームを抑止できた。
html {
touch-action: manipulation;
}
ちなみに、Twitter も Instagram も、ウェブサイト版はピンチズームを抑止していなかった。ピンチを抑止してしまうと、何かの拍子にズームされてしまった時に戻せなくなるので、ピンチは抑止しないでおこうと思う。