CSSでスクロールが連鎖するのを回避する古い方法とoverscroll-behaviorを使った新しいテクニック

スクロールの連鎖(スクロールチェーン)とは、ページ上にスクロールするコンテンツがあり、そのコンテンツをスクロールして終点に到達するとメインのコンテンツもスクロールしてしまう現象です。

モーダルにスクロールがある場合、スマホのナビゲーションにスクロールがある場合、固定サイドバーにスクロールがある場合など、スクロールチェーンしないように実装するCSSのテクニックを紹介します。

CSSでスクロールが連鎖するのを回避する古い方法とoverscroll-behaviorを使った新しいテクニック

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に追加します。

この解決方法はデスクトップのブラウザでは完璧に動作していましたが、iOSのSafariはこの解決方法を好みませんでした。これを機能させるには、body要素にposition: fixed;を追加する必要があります。

これで機能しますが、ブラウザが一番上までスクロールしてしまい、ユーザーが目の前の作業から気をそらしてしまいます。この解決方法は他の問題を引き起こします。

私はBen Frainの記事にあるピン留めされたもの以外の解決方法を知りません。記事によると、モーダルがアクティブになったら、bodyに下記を追加します。

私は2018年にクライアントのプロジェクトに取り組んだ際、「iOSスマホのbodyスクロールを防ぐことはできない」と伝えたことを覚えています。
クライアントはこう言いました。

プログラミングに不可能はありません。きっと解決方法があるはずです。

ちなみに「プログラミング」とはこの場合、CSSのことを指しています。私は多くの実装方法を試し、研究しましたが、完璧な解決方法はありませんでした。もし可能なら時を戻して、この記事で解説するoverscroll-behaviorによる解決方法があったならと思います。

今の解決方法: overscroll-behavior

overscroll-behaviorプロパティは、スクロール領域の境界に到達したときにブラウザが実行する動作を設定します。このプロパティはSafariを除く、すべての主要ブラウザでサポートされています。このプロパティはoverscroll-behavior-xoverscroll-behavior-yの省略形です。
参考: overscroll-behaviorのサポートブラウザ

overscroll-behaviorを定義すると、垂直と水平の両軸が定義されることに注意してください。それでは、設定可能な値について説明します。

overscroll-behavior: auto;

overscroll-behaviorプロパティのデフォルト値は、autoです。これによりスクロールチェーンが可能になります。スクロール要素があり、その境界に達すると、ブラウザはbodyコンテンツをスクロールし続けます。

overscroll-behavior: auto;の挙動

overscroll-behavior: auto;の挙動

overscroll-behavior: contain;

contain値はその名の通り、スクロールを要素の境界内に格納します。下図ではブルーで囲まれたラッパー内でのみスクロールができます。

overscroll-behavior: contain;の挙動

overscroll-behavior: contain;の挙動

overscroll-behavior: none;

none値はcontain値と同様の効果がありますが、それに加えてページの上部または下部に到達したときのバウンス効果を防ぐことができます。

overscroll-behaviorの使用方法

overscroll-behaviorプロパティがどのように機能するかがわかったところで、いくつかの便利な使用方法を紹介します。

スマホのナビゲーション

スマホのナビゲーションが長い場合にスクロールが速すぎると、コンテンツにスクロールチェーンが発生する可能性があります。

スマホのナビゲーション

ナビゲーションが長いと、スクロールチェーンが発生する

スクロールが収まっていないと、コンテンツもスクロールしてしまいます。それを避けるためには下記のCSSを使用します。

下記はナビゲーションの下が見えるように、半透明の背景を追加しました。overscroll-behavior-y: contain;をオフにすると、どのように動作するかに注目してください。

オフにすると、ボディスクロールが発生

興味深いのは、ナビゲーションが短く(つまりスクロールできない)、ユーザーが何の理由もなくスクロールしようとした場合、overscroll-behavior-y: contain;が設定されていても、ボディはスクロールしてしまうことです。

ナビゲーションが短い場合

残念ながら、これに対応するには冒頭で紹介した「ハック」以外の修正方法はわかりません。

サイドバーのナビゲーション

overscroll-behaviorのもう一つの便利な使い方は、サイドバーとメインがある場合です。サイドバーが固定されていて、コンテンツが長すぎる場合はスクロールしてしまう可能があります。

サイドバーのナビゲーション

ナビゲーションが長いと、スクロールチェーンが発生する

サイドバーをスクロールして終点に到達したときにメインがスクロールしないようにするには、下記のCSSを使用します。

チャットのコンポーネント

下記はFacebookにインスパイアされた、チャットのコンポーネントです。

チャットのコンポーネント

チャットを下までスクロールすると、スクロールチェーンが発生する

これはoverscroll-behaviorの完璧な使用例です。チャットの終点に到達したときにコンテンツをスクロールしないようにすることができます。

モーダルウインドウ

この記事で最初の例はモーダルだったので、繰り返しません。しかし、モーダルの中にリストが必要な場合があり、そのリストがスクロール可能な場合、スクロールチェインが発生しないようにする必要があります。

モーダルウインドウ

モーダルの中にさらにスクロールコンテンツがある場合

モーダルの中のリストに注目してください。これはスクロール可能なリストです。リストの終点に到達すると、モーダルのコンテンツがスクロールしてしまいます。これを避けるためには、overscroll-behaviorを使用します。

水平のリスト

Facebookでこの使用例を見つけました。ユーザーのリストを表示するセクションがあり、水平にスクロールします。

水平のリスト

リストのスクロールが終わると、スクロールチェーンが発生

これは、overscroll-behavior-xの適切な使用例です。

終わりに

CSSのoverscroll-behaviorは、何年もの間デベロッパーがハックで解決していた問題をシンプルに解決してくれる便利なプロパティです。

この記事があなたのお役に立てれば幸いです。
コメントや提案があれば、@shadeed9までお願いします。

sponsors

top of page

©2021 coliss