3

The goal is to detect the bottom of a page for an infinite scroll feature, such as those used for social media feeds. The solutions already suggested mostly involve something like:

if ($(window).scrollTop() + $(window).height() >= $(document).height()) {...}

This works great on the desktop but on a mobile device, the bottom of the page isn't being detected consistently.

The following are examples just to get an idea of what is happening. Both cases are occurring when fully zoomed out on a test page but the actual numbers vary depending on whether a page is zoomed in or not.

  • iPad Chrome: In landscape mode, $(window).scrollTop() + $(window).height() would consistently be about 15px shy of $(document).height()
  • Galaxy S4 Chrome: In portrait mode, $(window).scrollTop() + $(window).height() would consistently be about 36px shy of $(document).height()

In both cases, if the user was to zoom in sufficiently (usually a little bit is enough) on the page and then scroll to the bottom, the bottom of the page was detected and the infinite scroll goodness occurs. Needless to say, it's not ideal to assume the user will zoom in to trigger the infinite scroll. Interestingly, detecting the bottom works fine on the iPad Safari.

I've tried different solutions, including a solution suggested in another post involving getDocHeight() by James Padolsey to no avail. It didn't seem like James' solution would help because it looks like the problem is at $(window).scrollTop() but I tried it anyway.

if ($(window).scrollTop() + $(window).height() >= getDocHeight()) {...}

A simple workaround is to just add a bit to the left side of the statement, e.g., 100. However, this seems like a cheap hack that could be easily broken by different devices/browsers so something a bit more robust is preferable.

if ($(window).scrollTop() + $(window).height() + 100 >= $(document).height()) {...}

Thoughts/suggestions? Thank you in advance!

Update I took the tip from @Pomax and ran with it. With https://stackoverflow.com/a/7557433/1634817 in hand, the infinite paging is working now. I ended up adding an element at the end of the page and every time that element is visible to the user, the next set of content is loaded.

Related StackOverflow questions:

Community
  • 1
  • 1
jiminy
  • 1,612
  • 3
  • 18
  • 21
  • If you have infinite scroll, there is no bottom of the page. Only a "we ran out of content" limit. They may feel like the same thing; they are very much not. Once you go infinite scroll, abandon all thoughts of a "bottom". – Mike 'Pomax' Kamermans Apr 12 '14 at 06:22
  • I called it infinite scroll because that seems to be the way it's being called. It's also referred to as endless paging, autopaging, etc. The point being that once the bottom of a page is reached, more content is pulled. Hence, this requires detecting the bottom of the page. – jiminy Apr 12 '14 at 06:26
  • No, it requires detecting that the user is looking, or scrolling past, the last content entry. It has nothing to do with the bottom of a page. – Mike 'Pomax' Kamermans Apr 12 '14 at 06:29
  • How is that done? The samples that I've encountered involved code that detected the bottom of the page. – jiminy Apr 12 '14 at 06:35
  • 1
    easiest is to give the last content item an onscroll event listener, to see if it's in view. if it is, make that load more content. – Mike 'Pomax' Kamermans Apr 12 '14 at 06:37
  • OK, I'll take a look. I wonder if jQuery has viewport detection built-in. – jiminy Apr 12 '14 at 06:41
  • Sweet. Looks like this answers the viewport question: http://stackoverflow.com/questions/123999/how-to-tell-if-a-dom-element-is-visible-in-the-current-viewport/7557433#7557433 – jiminy Apr 12 '14 at 06:44
  • @Mike'Pomax'Kamermans Thanks a bunch. I got it to work with the viewport method and it works on all of the desktop and mobile browsers that I've tested so far. – jiminy Apr 12 '14 at 08:01

1 Answers1

1

Abbreviated solution using the viewport method, in case anyone wants it:

HTML

<body>
    <div id="content">
        <!-- Content goes here. //-->
        <div class="content-item"></div>
        <div class="content-item"></div>
    </div>
    <div id="get-additional">&nbsp;</div>
</body>

JS

$(function(){

    // Get elements early so we don't keep looking for them on every scroll.
    var contentDiv = $("#content");
    var getAdditionalDiv = $("#get-additional");

    // Upon initial load, if the content doesn't fill up the viewport, load additional content. The exact code will depend on your case but in my case, I needed to do a timeout instead of a regular while loop.
    setInterval(function(){if (isElementInViewport(getAdditionalDiv[0])) { appendAdditionalContent(); }}, 500);

    $(window).scroll(function() {
        // isElementInViewport uses getBoundingClientRect(), which requires the HTML DOM object, not the jQuery object. The jQuery equivalent is using [0] as shown below.
        if (isElementInViewport(getAdditionalDiv[0])) {
            appendAdditionalContent();
        }
    });

    function appendAdditionalContent() {
        // Create/get the additional content (e.g., an ajax call).
        var $additionalContent = ... ;

        // Prevent infinite loops. Get rid of the additional div trigger once there is no more content to pull.
        if ( ... there is no $additionalContent ...) {
            getAdditionalDiv.remove();
        } else {
            // Append the additional content.
            contentDiv.append($additionalContent);
        }
    }

    // This function is verbatim from https://stackoverflow.com/a/7557433/1634817. As of this writing, this one is the currently recommended solution. There is a more robust solution in the thread as well. Use whichever you think best but both worked for me.
    function isElementInViewport (el) {
        var rect = el.getBoundingClientRect();

        return (
            rect.top >= 0 &&
            rect.left >= 0 &&
            rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && //* or $(window).height()
            rect.right <= (window.innerWidth || document.documentElement.clientWidth) //* or $(window).width()
        );
    }
});

References

Community
  • 1
  • 1
jiminy
  • 1,612
  • 3
  • 18
  • 21