「端っこ」におけるスクロールの挙動を制御する overscroll-behavior プロパティ

※この記事の内容は、まだブラウザに実装されていない内容を含みます。また、勧告前の仕様について言及しているため、最新の仕様では変更になっている場合があります。

要約

overscroll-behavior プロパティを使うと、スクロール境界(端っこ)におけるブラウザデフォルトの挙動を上書きすることができます。例えば、ブラウザが持っている「下方向に引っ張ってリロード」する機能や、スクロールが親要素に伝わる「スクロールチェーン」の挙動を無効化することができます。

はじめに

主にタッチデバイスにおいて、無効化したいのにできない、スワイプ操作やスクロールにまつわる困った挙動が3種類ありました。

  1. 「もうこれ以上スクロールができない」ことを表すインタラクション
  2. スクロールが親に伝播してしまう「スクロールチェーン」
  3. 左右へのスワイプで行う履歴の前後ナビゲーション

「もうこれ以上スクロールができない」ことを表すインタラクションはお馴染みです。iOS Safariならば端っこにぶつかってビヨヨンと跳ね返る感じになり、Androidでは画面端にちょっとした効果が表示されることで「これ以上スクロールできない」ことを知らせます。

スクロールチェーン(scroll chaining)とは何かというと、 overflow: autooverflow: scroll を持った要素が端っこまでスクロールされている状態で、さらにその方向にスクロールしようとすると、親要素(たいてい )が勝手にスクロールしてしまうという現象です。これに困らされた制作者は多いでしょう。

これらの挙動は、特定のタイプのUIを実装するときに、無効化したくなるケースがしばしばあります。

例えばアプリっぽいUIを実装していて、Twitterアプリに見られるような「引っ張ってリロード」機能をつけようとしているとき、ブラウザネイティブのビヨヨン(通称ラバーバンド効果)は無効にしたいでしょう。あるいはモーダルダイアログを前面に被せるなら、背後のコンテンツがスクロールされてしまうのは困ります。また、タッチを主軸にしたインターフェースを実装しているときは、不意に履歴を戻らないようにしたくなります。

JavaScriptを駆使しても、これらの挙動を完全に無効化するのはできないのですが、 overscroll-behavior プロパティを使うと、いとも簡単にこれらの挙動を抑制することができます。

overscroll-behavior プロパティ

overscroll-behavior プロパティは3種類の値をとります。 auto, contain, none です。

auto
デフォルト値。ブラウザのデフォルトの挙動に任せる。
contain
スクロールの挙動を、スクロール要素の外側にはみ出ないようにする。つまり前述の2番(スクロールチェーン)と3番(スワイプナビゲーション)を無効化する。
none
contain を指定した時と同じ効果に加えて、1番(スクロール端のビヨヨン効果等)も無効化する。

使い方

使い方は簡単で、html要素または、 overflow: auto/scroll を設定している任意の要素に対して、 overscroll-behavior: contain または overscroll-behavior: none を指定すればオーケーです。

html {
  // ビヨヨン効果を無効化する
  overscroll-behavior: none;
}
.modal-container {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  overflow-y: auto;
  // 親要素にスクロールが伝わらないようにする
  overscroll-behavior: contain;
}

派生プロパティの overscroll-behavior-xoverscroll-behavior-y を使うことで、挙動の無効化を左右方向のみ、上下方向のみに制限することができます。これにより、通常スクロールのビヨヨン効果を維持しつつ、ブラウザ履歴のナビゲーションだけ無効化するといったことが可能です。

html.disable-navigation {
  // 左右スワイプによる履歴ナビゲーションを無効化する
  overscroll-behavior-x: none;
}

ブラウザ対応状況

この仕様はまだ Editor’s Draft 状態であり、将来的に実装が行き渡るかどうかは謎です。しかし要望は大きいはずなので、ぜひとも勧告までこぎつけてほしいと思います。

以下は執筆時(2017年11月16日)時点の各ブラウザ対応状況です。

  • Chrome (Desktop) … バージョン63にて対応 ※1
  • Chrome (Mobile) … バージョン63にて対応 ※1
  • Firefox … バージョン59にて対応
  • Safari … 開発中
  • Edge … Edge 18にて対応
  • IE … 未対応 ※2

※1 … overscroll-behavior-x, overscroll-behavior-y プロパティは未対応 対応しているようです
※2 … IE10以降とEdgeには -ms-scroll-chaining という類似のプロパティがあり、これを使用すると親要素へのスクロール伝播は抑制することができる。ただし効果はタッチ端末に限る

参考

余談

今まさに手がけている案件でスクロールチェーン問題について指摘を受けていて、どうしようかと悩んでいた。そんな折にGIF動画付きの解説記事がアップされて、ドンピシャなプロパティがあるんだ! と飛びついたところだった。ただし、まだまだ実装はこれからという状況のようで、すぐに使うことはできなそう。ありがたいプロパティなので今後に期待したい。

スクロールチェーンの抑止については、以前にJavaScriptで頑張って実装してみようとしたことがあり実用レベルではあるのだけど、標準仕様になってくれるに越したことはないので。