overscroll-behaviorがお手軽! モーダルUI等のスクロール連鎖を防ぐ待望のCSS

96
59

2022年9月にSafari 16がリリースされ、すべての主要なブラウザで、CSSのoverscroll-behaviorプロパティが利用可能になりました。ChromeやFirefoxでは、2018年3月からサポートされていたプロパティだったので、耳にしたことがある方も多いのではないでしょうか?

overscroll-behaviorプロパティは、スクロール可能なコンテンツ(以下、スクロールコンテナー)を端までスクロールした時の動作を制御できるプロパティです。このプロパティを利用することで次のような問題を解決できます。

  • 背面のコンテンツにスクロールが伝達する動作を抑制する
  • ダイアログやハンバーガーメニューといった、画面固定したコンテンツをスクロールする場合も、背面がスクロールされる問題を防ぐ
  • ブラウザのPull-to-Refresh(ブラウザを上方向にスワイプしてリロードする)を抑制する

画面固定したコンテンツで背面がスクロールされる問題は、『HTMLでモーダルUIを作るときに気をつけたいこと』でも取り上げていて、JavaScriptで制御する対策を紹介しました。同じ問題をoverscroll-behaviorプロパティでよりシンプルに解決できるようになります。

本記事では、overscroll-behaviorプロパティで制御できる動作と使い方について紹介します。

overscroll-behaviorとは

overscroll-behaviorは、スクロールコンテナーを境界(端)までスクロールしたあと、さらに同じ方向にスクロールした時の動作を制御するプロパティです。

動作は大きく2つに分類されます。ひとつは背面にスクロールコンテナーがあれば、背面にスクロールが伝達するスクロールチェーンと呼ばれる動作です。もうひとつはPull-to-Refresh(ブラウザを上方向にスワイプしてリロードする)といった、オーバースクロール(スクロール可能な領域を少し超えて行われること)の動作です。

▼背面のコンテンツにスクロールが伝達される例 背面のコンテンツがスクロールされる例

▼Pull-to-Refreshの例 Pull-to-Refreshの例

スクロール可能なコンテンツでプロパティを利用できる

overflowプロパティのようにx軸、y軸をそれぞれ制御するoverscroll-behavior-xoverscroll-behavior-yというプロパティが存在し、2つの軸を制御するoverscroll-behaviorプロパティがあります。

overflow: autoおよびoverflow: scrollが指定されたスクロールコンテナーに対してoverscroll-behaviorプロパティを指定することで適用されます。

overflowプロパティが設定されていた場合でも、スクロールバーが発生しないスクロール不可能な要素だった場合は、overscroll-behaviorプロパティは無視されます。

overscroll-behaviorが適用される例

<div class="container">
  <div class="item"></div>
</div>
.container {
  width: 100px;
  height: 25px; /* 親要素が子要素より小さくスクロール可能 */
  overflow-y: auto;
  overscroll-behavior-y: none; /* 適用される */
}
.item {
  width: 100%;
  height: 50px;
}

▼スクロール不可能なため、overscroll-behaviorが無視される例

<div class="largeContainer">
  <div class="item"></div>
</div>
.largeContainer {
  width: 100px;
  height: 100px; /* 親要素が子要素より大きくスクロール不可能 */
  overflow-y: auto;
  overscroll-behavior-y: none; /* 無視される */ 
}
.item {
  width: 100%;
  height: 50px;
}

値の初期値にはautoが指定され、containまたはnoneで制御する

overscroll-behaviorの値は、auto | contain | none の3つが存在します。初期値にはautoが指定されます。

説明
auto スクロールチェーンやオーバースクロールは、デフォルトの動作を行います。
contain スクロールチェーンを抑制し、オーバースクロールの動作を維持します。
none スクロールチェーンと、オーバースクロールの動作を抑制します。

3つ値の具体的な動作は、次のサンプルで確認できます。overscroll-behaviorプロパティがcontainまたはnoneだった場合、背面のコンテンツにスクロールが伝達しないことを確認できます。

加えてcontainは、オーバースクロールの動作を維持します。このサンプルでは、コンテンツを超えて上下にバウンスする効果を確認できます。(次のGIF画像の2番目)

効果が有効かどうかは、OSやブラウザによって異なりますが、モバイルのPull-to-Refreshが有効なブラウザから確認できると思います。

3つの値の使用例

どのような使い方ができるのか、作例をいくつか用意しましたのでご紹介します。実装の参考にしてみてください。

画面固定で表示するUIの作例

画面固定で表示されるダイアログとハンバーガーメニューをdialog要素で実装し、overscroll-behavior: containで制御した作例です。

表示されるコンテンツを画面サイズにして、背景を含めたスクロール制御をしています。また、表示されるコンテンツをスクロール可能なサイズにしなければoverscroll-behaviorプロパティは適用されないため、縦幅をheight: calc(100% + 1px);として1pxだけスクロールできるように調整しています。

ダイアログとハンバーガーメニューの動作例

ハンバーガーメニューをdialog要素で実装しているのは、少し変わったアプローチかもしれませんが、キーボード操作を考慮するために使用しています。詳しく知りたい方は、次の記事も参考にしてみてください。

ルート要素を制御する作例

ルートとなる要素にoverscroll-behaviorプロパティを指定することも可能です。次の作例では、overscroll-behavior-y: noneを指定しています。ブラウザのPull-to-Refreshが確認できるデバイスで見ると、Pull-to-Refreshが抑制されていることを確認できます。

ルート要素を制御する例

ブラウザごとにoverscroll-behaviorプロパティを指定するルートの要素が異なります。ChromeやEdgeなどChromium系のブラウザでは、body要素を指定して、SafariやFirefoxではhtml要素に指定することで動作します。

html,
body {
  overscroll-behavior-y: none;
}

iframe要素は、ブラウザによって異なる動作をするので注意

最後に、iframe要素にoverscroll-behavior: noneを設定した作例を紹介します。この作例はChromeやEdgeなどChromium系のブラウザでのみ動作します。

MDNのドキュメントでは、iframe要素はスクロールコンテナーではないため、overscroll-behaviorプロパティでスクロールを制御できないという説明があります。実際にSafariやFirefoxでは動作せず、ブラウザによって異なる動作をするため注意が必要です。

ブラウザのサポート状況

Can I use…によると、Chrome、Firefox、Safari、Edgeの最新バージョンで利用可能と記載されています。

Can I useによるサポート状況一覧

▲Chrome 65(2018年3月)以上、Edge 79(2020年1月)以上、Safari 16.0(2022年9月)以上、Firefox 59(2018年3月)以上でサポートされています。

まとめ

overscroll-behaviorプロパティで制御できる動作や使い方の紹介をしました。とくにスクロールチェーンの制御は、これまではbody要素にoverflow: hiddenを追加したり、JavaScriptで制御するなど一工夫が必要でした。ですが、overscroll-behaviorプロパティを利用することでシンプルに制御できるようになります。

実務でも画面固定のUIは実装する機会が多いので、overscroll-behaviorプロパティが役立つでしょう。

参考サイト

古舘 和志

フロントエンドエンジニア。ウェブデザイナーのようなHTMLコーダーからフロントエンドエンジニアに転身。現在は岩手からリモートで勤務中。

この担当の記事一覧