💠

背景スクロールの抑制

2024/11/04に公開

はじめに

モーダルなどを表示する際に、背景のスクロールを止める実装をすることがあると思います。
理由としては以下のような感じで実装を求められるかなと思います。

  • ユーザーの視線をモーダルに集中させるため
  • モーダル自身にスクロールがある場合でも、モーダルのみをスクロールできるためユーザーの期待通りの操作ができ質が向上する

その際によくやるのがbodyにoverflow: hidden;を付与する方法でした。
しかし、ios18ではこの方法では完全に止めることができなくなりました。※ios17でも完全に抑制はできてはないです。

調査結果

以下の実装方法を検証しました。

  • bodyにoverflow: hidden;
  • html,bodyにoverflow: hidden;
  • position: fixed; + 抑制解除時に元の位置に戻す

overflow: hidden;のパターン

スクロール抑制でよく見かけるパターンです。
一見このパターンでも制御できているように見えますが、実は完全にはできていません。
このパターンではアドレスバーが表示している際には制御ができますが、アドレスバーが非表示の際に抑制ができていないです。

ios16からこのパターンでスクロールを制御できるという情報が結構溢れていますが、抑制されていなかったんですね..確認大事自戒します。

position: fixed; + 抑制解除時に元の位置に戻すパターン

このパターンではアドレスバーの有無に関わらず制御ができます。
bodyにposition: fixed;を付与することでスクロールを制御することができますが、これだけだとモーダルを閉じた時に画面の一番上までスクロールしてしまいます。
そのためスクロールした位置を取得してその位置をCSSに追加すればbodyはスクロールして一番上までこないので問題が解決します。

以下のcodepenのコードで検証しました。興味ある方は自身のデバイスでお試しください。

終わりに

iosでoverflow: hiddenではなくclipにすれば解決するというのを見かけたので革命だ!と思って色々調べたのが始まりだったのですが全然スクロール抑制できていなくて結局他の方法がベターなんじゃないかという結論になりました..
他にもpreventDefault()を使用する方法もありますが、他の箇所での操作に問題が発生しそうな印象があるので、今回は割愛しました。それも込みでposition: fixed; + 抑制解除時に元の位置に戻すパターンが今対応するなら一番いいのかなと思います。

Discussion