Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to detect bottom of page? Problems on mobile

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:

  • jQuery Detect Bottom of Page on Mobile Safari/iOS
  • Check if a user has scrolled to the bottom
  • detect scroll to bottom on dynamic page
like image 539
jiminy Avatar asked Jan 28 '26 19:01

jiminy


1 Answers

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

  • How to tell if a DOM element is visible in the current viewport?
  • document.getElementById vs jQuery $()
like image 171
jiminy Avatar answered Jan 31 '26 10:01

jiminy



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!