CSSでスクロールが連鎖するのを回避する古い方法とoverscroll-behaviorを使った新しいテクニック
Post on:2021年11月11日
スクロールの連鎖(スクロールチェーン)とは、ページ上にスクロールするコンテンツがあり、そのコンテンツをスクロールして終点に到達するとメインのコンテンツもスクロールしてしまう現象です。
モーダルにスクロールがある場合、スマホのナビゲーションにスクロールがある場合、固定サイドバーにスクロールがある場合など、スクロールチェーンしないように実装するCSSのテクニックを紹介します。
Prevent Scroll Chaining With Overscroll Behavior
by Ahmad Shadeed
下記は各ポイントを意訳したものです。
※当ブログでの翻訳記事は、元サイト様にライセンスを得て翻訳しています。
はじめに
position: fixed;
の要素があるとします。この要素にスクロール機能がある場合、要素の下境界に到達すると、ブラウザはbody
要素のスクロールを続けることに気がつくでしょう。しかし、これは望ましくない混乱を招くスクロールです。ありがたいことに、CSSでこの問題を修正できます。
この記事ではCSSのoverscroll-behavior
プロパティについて、このプロパティが解決する問題とその仕組み、そしてどこで使えるのかを説明します。
スクロールチェーンとは
まずは、よくある問題を取りあげます。
ビューポートの中央にモーダルダイアログが配置されています。そして、モーダルダイアログの下には、実際のWebページのコンテンツがあります。
中央にモーダルダイアログがあり、その下にコンテンツがある
モーダルコンテンツをスクロールして終わりに到達すると、ブラウザは代わりにメインページのコンテンツをスクロールさせます。これはスクロールチェーンと呼ばれるものです。デフォルトの動作ですが、overscroll-behavior
という新しいCSSのプロパティでオーバーライドできるようになりました。
モーダルのスクロールが終わったら、その下のコンテンツがスクロールしてしまう
この動作は必要ないことが多く、ユーザーがモーダルコンテンツに集中できなくなる可能性があります。上の図では、モーダルの終わりに到達したとき、コンテンツにスクロールが連鎖してしまうことに注目してください。
スクロールチェーン(連鎖的スクロール)や過スクロールのふるまいについては、下記をご覧ください。
古い解決方法
これまでは、JavaScriptでbody
要素にoverflow: hidden;
を付与することで解決していました。モーダルが開かれると、オーバーフローを担当するクラスをbody
に追加します。
1 2 3 4 5 6 7 |
body.modal-open { overflow: hidden; } .modal.is-open { display: block; } |
この解決方法はデスクトップのブラウザでは完璧に動作していましたが、iOSのSafariはこの解決方法を好みませんでした。これを機能させるには、body
要素にposition: fixed;
を追加する必要があります。
1 2 3 4 5 6 7 8 |
body.modal-open { position: fixed; overflow: hidden; } .modal.is-open { display: block; } |
これで機能しますが、ブラウザが一番上までスクロールしてしまい、ユーザーが目の前の作業から気をそらしてしまいます。この解決方法は他の問題を引き起こします。
私はBen Frainの記事にあるピン留めされたもの以外の解決方法を知りません。記事によると、モーダルがアクティブになったら、body
に下記を追加します。
1 2 3 4 5 6 7 8 |
.bg-scrolling-element-when-modal-active { /* when modal active */ touch-action: none; -webkit-overflow-scrolling: none; overflow: hidden; /* Other browsers */ overscroll-behavior: none; } |
私は2018年にクライアントのプロジェクトに取り組んだ際、「iOSスマホのbody
スクロールを防ぐことはできない」と伝えたことを覚えています。
クライアントはこう言いました。
ちなみに「プログラミング」とはこの場合、CSSのことを指しています。私は多くの実装方法を試し、研究しましたが、完璧な解決方法はありませんでした。もし可能なら時を戻して、この記事で解説するoverscroll-behavior
による解決方法があったならと思います。
今の解決方法: overscroll-behavior
overscroll-behavior
プロパティは、スクロール領域の境界に到達したときにブラウザが実行する動作を設定します。このプロパティはSafariを除く、すべての主要ブラウザでサポートされています。このプロパティはoverscroll-behavior-x
とoverscroll-behavior-y
の省略形です。
参考: overscroll-behaviorのサポートブラウザ
overscroll-behavior
を定義すると、垂直と水平の両軸が定義されることに注意してください。それでは、設定可能な値について説明します。
overscroll-behavior: auto;
overscroll-behavior
プロパティのデフォルト値は、auto
です。これによりスクロールチェーンが可能になります。スクロール要素があり、その境界に達すると、ブラウザはbody
コンテンツをスクロールし続けます。
overscroll-behavior: auto;
の挙動
overscroll-behavior: contain;
contain
値はその名の通り、スクロールを要素の境界内に格納します。下図ではブルーで囲まれたラッパー内でのみスクロールができます。
overscroll-behavior: contain;
の挙動
overscroll-behavior: none;
none
値はcontain
値と同様の効果がありますが、それに加えてページの上部または下部に到達したときのバウンス効果を防ぐことができます。
overscroll-behaviorの使用方法
overscroll-behavior
プロパティがどのように機能するかがわかったところで、いくつかの便利な使用方法を紹介します。
スマホのナビゲーション
スマホのナビゲーションが長い場合にスクロールが速すぎると、コンテンツにスクロールチェーンが発生する可能性があります。
ナビゲーションが長いと、スクロールチェーンが発生する
スクロールが収まっていないと、コンテンツもスクロールしてしまいます。それを避けるためには下記のCSSを使用します。
1 2 3 4 |
.nav { overscroll-behavior-y: contain; overflow-y: auto; } |
下記はナビゲーションの下が見えるように、半透明の背景を追加しました。overscroll-behavior-y: contain;
をオフにすると、どのように動作するかに注目してください。
オフにすると、ボディスクロールが発生
興味深いのは、ナビゲーションが短く(つまりスクロールできない)、ユーザーが何の理由もなくスクロールしようとした場合、overscroll-behavior-y: contain;
が設定されていても、ボディはスクロールしてしまうことです。
ナビゲーションが短い場合
残念ながら、これに対応するには冒頭で紹介した「ハック」以外の修正方法はわかりません。
サイドバーのナビゲーション
overscroll-behavior
のもう一つの便利な使い方は、サイドバーとメインがある場合です。サイドバーが固定されていて、コンテンツが長すぎる場合はスクロールしてしまう可能があります。
ナビゲーションが長いと、スクロールチェーンが発生する
サイドバーをスクロールして終点に到達したときにメインがスクロールしないようにするには、下記のCSSを使用します。
1 2 3 |
.aside { overscroll-behavior-y: contain; } |
チャットのコンポーネント
下記はFacebookにインスパイアされた、チャットのコンポーネントです。
チャットを下までスクロールすると、スクロールチェーンが発生する
これはoverscroll-behavior
の完璧な使用例です。チャットの終点に到達したときにコンテンツをスクロールしないようにすることができます。
1 2 3 |
.aside { overscroll-behavior-y: contain; } |
モーダルウインドウ
この記事で最初の例はモーダルだったので、繰り返しません。しかし、モーダルの中にリストが必要な場合があり、そのリストがスクロール可能な場合、スクロールチェインが発生しないようにする必要があります。
モーダルの中にさらにスクロールコンテンツがある場合
モーダルの中のリストに注目してください。これはスクロール可能なリストです。リストの終点に到達すると、モーダルのコンテンツがスクロールしてしまいます。これを避けるためには、overscroll-behavior
を使用します。
1 2 3 4 5 |
.list-wrapper { overscroll-behavior-y: contain; overflow-y: auto; max-height: 130px; } |
水平のリスト
Facebookでこの使用例を見つけました。ユーザーのリストを表示するセクションがあり、水平にスクロールします。
リストのスクロールが終わると、スクロールチェーンが発生
これは、overscroll-behavior-x
の適切な使用例です。
1 2 3 |
.list { overscroll-behavior-x: contain; } |
終わりに
CSSのoverscroll-behavior
は、何年もの間デベロッパーがハックで解決していた問題をシンプルに解決してくれる便利なプロパティです。
この記事があなたのお役に立てれば幸いです。
コメントや提案があれば、@shadeed9までお願いします。
sponsors