MENU

【iOS】モーダル表示時に背景スクロールが止まらない原因と解決策

モーダルとかオーバーレイ表示した時に、背景のスクロール止めたいですよね。
普通は overflow: hidden で止まるんですが、iOSだとこれが効かない!!

実案件でめちゃくちゃハマったので、原因と解決策をまとめました🐧

目次

まず結論

overflow: hidden ではなく、position: fixed で body を固定するのが正解です!!

let savedScrollY = 0;

// スクロールロック
function lockScroll() {
  savedScrollY = window.scrollY;
  document.body.style.overflow = 'hidden';
  document.body.style.position = 'fixed';
  document.body.style.top = `-${savedScrollY}px`;
  document.body.style.width = '100%';
}

// スクロール解除
function unlockScroll() {
  document.body.style.removeProperty('overflow');
  document.body.style.removeProperty('position');
  document.body.style.removeProperty('top');
  document.body.style.removeProperty('width');
  window.scrollTo(0, savedScrollY);
}

これでiOSでもPCでも確実にスクロールが止まります!!

何が起きたか

サイトのトップに言語選択モーダルを実装してたんですが、PCでは問題なく動いてました。

が、iPhoneで確認したらモーダルの後ろがスクロールできちゃう…!!

overflow: hidden はちゃんとかけてるのに、です。

「え、なんで…?」ってなりました。

原因:WebKit がタッチスクロールに overflow: hidden を適用しない

調べたら、WebKit Bug #153852 として報告されている既知のバグでした。

そして重要なのが、Safari だけの話じゃないということ!!

iOSではAppleの制約で、Chrome も Firefox も Edge も全部 WebKit エンジンを使っています。
なのでiOS上のどのブラウザでも同じ問題が起きます。

実際に iPhone の Chrome でも再現しました。
Safari だけかと思ったら全ブラウザだったので焦りました…!!

なぜ position: fixed で解決できるのか

position: fixed をかけると、body がビューポートに固定されてドキュメントフローから外れます。
つまりスクロールする対象自体がなくなるので、iOSでも確実に止まります!!

ポイントは3つ:

  • ✅ ロック時に window.scrollY を保存して top: -Npx で見た目のズレを防ぐ
  • width: 100% を忘れない(忘れると body の幅が潰れる)
  • ✅ 解除時に scrollTo() で元の位置に戻す(忘れるとページトップに飛ぶ)

やりがちなNG実装

自分が試してダメだったパターンも晒しておきます!!

やったこと結果
body { overflow: hidden }❌ iOSのタッチスクロールに効かない
html { overflow: hidden }❌ 同じく効かない
touch-action: none❌ 一部ブラウザで効かない

全部試した上で position: fixed に辿り着きました。
最初からこれやっとけばよかった…!!

まとめ

  • iOS では overflow: hidden だけではタッチスクロールが止まらない
  • Safari だけじゃなく iOS の Chrome や Firefox でも発生する(全部 WebKit だから)
  • position: fixed + スクロール位置の保存・復元が一番確実!!

モーダル実装する時はとりあえずこの方法でやっていきましょー!!🐧

参考

以上!!
誰かのお役に立てれば嬉しいです🐧

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

目次