Help us understand the problem. What is going on with this article?

結局「下からのスクロール位置」を取得するにはどうすればいいのか

More than 3 years have passed since last update.

最近の Web サービスでよくある「下までスクロールしたら次のコンテンツを読み込む(オートページャライズ)」を実装するためには、当然ですが「下までスクロールしたかどうか」を検出する必要があります。

これが簡単そうに見えて意外と面倒臭く、自分も毎回思い出すのに時間がかかってしまいます。

御託はいいから結論を先に言え

これでよさそう

function getScrollBottom() {
  var body = window.document.body;
  var html = window.document.documentElement;
  var scrollTop = body.scrollTop || html.scrollTop;
  return html.scrollHeight - html.clientHeight - scrollTop;
}

以下、解説です

どんな値が取得できるか

まず、使いそうな要素

  • document.body body 要素
  • document.documentElement 文書全体を表す要素 (html要素)

ややこしいので、これ以降では body と書いてあったら document.body, html と書いてあったら document.documentElement のことだと思ってください。

次に、使いそうなプロパティ

  • scrollTop 要素内のスクロール量
  • clientHeight 要素の高さ
  • scrollHeight 要素内のスクロールできる高さ

clientHeightscrollHeight は何が違うんじゃ、って話ですが、要素の高さを超えるくらい要素の内容が多い場合、要素そのものの高さが clientHeight で要素の内容の高さが scrollHeight になります。

しかし僕はあまり頭がよくなく、「そんなこと言われてもよくわからん、直感的にわかるようにして!!!」という感じだったので、こういうツールを作りました。

http://hoto17296.github.io/browser-height-api-test/

スクロールしたり body の高さを変えてみたりすることで、それぞれの値がどう変化するのかがわかると思います。

スクロール量を取得する

scrollTop には罠があって、ページ全体のスクロール量を取得したい場合は ブラウザによって取得方法が違います

  • WebKit 系 ( Safari, Chrome 等) や Edge では body.scrollTop
  • IE, Firefox, Opera などでは html.scrollTop

ブラウザの対応していない方法で取得しようとする(例えば Firefox の document.body.scrollTop)と、必ず 0 が返ってきます。

そのため、正しくスクロール量を取得するためには

var body = document.body;
var html = document.documentElement;

var scrollTop = body.scrollTop || html.scrollTop;

こうする必要があります。

ちなみに、scrollTop だけでなく body.scrollHeight もブラウザによって値が変わるのであまり使わないほうがよさそうです。

計算する

必要な値が取得できたので、あとは計算するだけです。

ここで気をつけないといけないのは、コンテンツ量によって body の高さが変わるので body の高さが画面のよりも長い場合と短い場合の両方に対応できるようにしたほうがいいということです。

body が長い場合

01.png

body が長いとき、「ドキュメント全体の高さ」は body.clientHeight または html.scrollHeight で取得することができます。

つまり「下からのスクロール位置」は

scrollBottom = (ドキュメント全体の高さ) - scrollTop - html.clientHeight

このように求めることができます。

body が短い場合

02.png

body が短いときは、そもそもスクロールしないので「下からのスクロール位置」は常に 0 であってほしいと思います。

bodyが長いときの計算式
scrollBottom = (ドキュメント全体の高さ) - scrollTop - html.clientHeight 

この式に当てはめると、期待する scrollBottom0scrollTop はこの場合は常に 0 なので、(ドキュメント全体の高さ) == html.clientHeight のときに期待する値が得られそうです。

(ドキュメント全体の高さ) は body.clientHeighthtml.scrollHeight のいずれかだったので、このうち (ドキュメント全体の高さ) == html.clientHeight を満たすのは html.scrollHeight のみとなります。

ということで、ドキュメント全体の高さを取得するには html.scrollHeight を使うと良さそうです。

つまり、

scrollBottom = html.scrollHeight - scrollTop - html.clientHeight

これで「下からのスクロール位置」を求めることができそうです。
これをちゃんとした JavaScript に直すと、冒頭に書いたコードになります。

オマケ

var scrollBottomEvent = window.document.createEvent('UIEvents');
scrollBottomEvent.initUIEvent('scrollBottom', true, false, window, 1);
window.document.addEventListener('scroll', function() {
  var body = window.document.body;
  var html = window.document.documentElement;

  var scrollTop    = body.scrollTop || html.scrollTop;
  var scrollBottom = html.scrollHeight - html.clientHeight - scrollTop;

  if ( scrollBottom <= 0 ) {
    window.document.dispatchEvent( scrollBottomEvent );
  }
});

こういうカスタムイベントを作っておくと

document.addEventListener('scrollBottom', function() {
  // 下までスクロールしたときの処理
});

下までスクロールしたときのイベント処理がシンプルに書けて便利です。

hoto17296
ゆとりデータ分析マン
https://hoto.me/
churadata
沖縄で データ分析 / 機械学習 / Deep Learning をやっている会社です
https://churadata.okinawa/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした