「端っこ」におけるスクロールの挙動を制御する 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 … 不明
  • IE/Edge … 未対応 ※2

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

参考

余談

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

スクロールチェーンの抑止については、以前にJavaScriptで頑張って実装してみようとしたことがあるのだけど、抜け漏れなく作りこむことができておらず、ムグムグ……。