jQuery: how to tell if you’re scroll to bottom?

This is a question a jQuery user asked recently. It’s a simple question without a simple answer. There is no inverse equivalent to scrollTop=0 (i.e. scrollBottom=0) so the solution requires some thought.

The scenario is this — we have a fixed height div with overflow:auto and we want to use JavaScript to programmatically scroll to bottom and also to execute some code if we’re at the bottom. Our div looks like this (using inline styles for the sake of this example):

<div id="box" style="height:300px; overflow:auto;">
  <!-- Your content goes here -->
</div>

To scroll to bottom programmatically we do:

$('#box').animate({scrollTop: $('#box')[0].scrollHeight});

And to check whether we’re scrolled to bottom:

var elem = $('#box');
if (elem[0].scrollHeight - elem.scrollTop() == elem.outerHeight()) {
  // We're at the bottom.
}

That’s pretty easy, right? As noticed scrollHeight is the key to this solution.

A bit of info about scrollHeight: First introduced by MSIE and supported since version 4, [1] scrollHeight gets the height of an element’s content including padding but not margins. Though scrollHeight is currently supported by all major browsers it is not part of a W3C recommendation so still considered proprietary. [2]

Now, some of you reading this might not like scrollHeight because it’s not a W3C recommendation. So for the interest of this group let’s explore an alternative solution.

Your first stab at the alternative to check whether we’re scrolled to bottom might look something like this:

if ($('#box').scrollTop() == $('#box').outerHeight()) {
  // We're at the bottom.
}

Novel, but that doesn’t work! scrollTop is quite an arbitrary value. In our case depending on which browser you choose the answer could be anything from 244px (Safari) to 289px (IE7). Clearly this is not a viable solution.

To determine whether we’re truely at rock bottom we have to get the height of the element’s content and do a calculation based on that. Now we’re immediately faced with another problem — there is no sane way of determining the actual height of an element’s content because .outerHeight() always gives 300px plus padding as the answer. We could use an inner div to get over this problem:

<div id="box" style="height:300px; overflow:auto;">
  <div class="inner">
    <!-- Your content goes here -->
  </div>
</div>

So now we have a way of determining content height we can scroll to bottom:

$('#box').animate({scrollTop: $('#box > .inner').outerHeight()});

And to check whether we’re scrolled to bottom we use the offset method:

var elem = $('#box');
var inner = $('#box > .inner');
if ( Math.abs(inner.offset().top) + elem.height() + elem.offset().top >= inner.outerHeight() ) {
  // We're at the bottom!
}

Not as striaght forward as scrollHeight aye?

Here’s a test page encompassing the stuff talked about in this article.

References:
[1] scrollHeight Property
[2] element.scrollHeight