Explain Codes LogoExplain Codes Logo

Check if a user has scrolled to the bottom (not just the window, but any element)

javascript
infinite-scroll
scroll-events
debouncing
Nikita BarsukovbyNikita Barsukov·Jan 2, 2025
TLDR

Evidence of a bottom scroll within an element can be established by comparing the scrollTop (scroll offset), clientHeight (visible area of the element), and scrollHeight (total scrollable height). The bottom is reached if the sum of scrollTop and clientHeight equals or is larger than the scrollHeight.

element.addEventListener('scroll', () => { if (element.scrollTop + element.clientHeight >= element.scrollHeight) { console.log("We've hit rock bottom, guys!"); // Because geologists dig deep } });

With a debounce function in place, the checks are done smoothly, enhancing your performance score:

const debounce = (func, delay) => { let inDebounce; return function() { const context = this; const args = arguments; clearTimeout(inDebounce); inDebounce = setTimeout(() => func.apply(context, args), delay); }; }; element.addEventListener('scroll', debounce(() => { if (element.scrollTop + element.clientHeight >= element.scrollHeight) { console.log("We've hit rock bottom, guys!"); // Funny because it's true } }, 100));

Brace yourself for scroll events

Scroll events can turn a smooth user experience into a jerky one if not handled with care. Debouncing or throttling these events keeps the scrolling action smooth and prevents overloading the browser.

The Math.max() function is used to determine the document height in a consistent manner across different browsers:

const getDocHeight = () => { return Math.max( document.body.scrollHeight, document.documentElement.scrollHeight, document.body.offsetHeight, document.documentElement.offsetHeight, document.body.clientHeight, document.documentElement.clientHeight ); };

A dynamic content loading strategy is perfect for achieving infinite scrolling effects, bringing about an engaging user experience by providing fresh content as the user scrolls.

Bottomless truth about infinite scroll

Don't get stuck in a loop

Infinite scroll can cause an issue where the same content could get loaded multiple times. This can be avoided by tracking the state of your on-going Ajax requests, or by using a simple boolean flag.

Precision is key

For a more precise detection, you can trigger the event even before the user has reached the bottom:

const threshold = 100; glass.addEventListener('scroll', () => { const nearBottom = glass.scrollHeight - glass.scrollTop - threshold; if (nearBottom <= glass.clientHeight) { console.log('Shaken, not stirred!'); // Because Bond didn't need to reach the bottom } });

Look for reliable alternatives

In case scrollHeight and clientHeight don’t prove to be reliable, consider using getBoundingClientRect() for more accurate results.

Enhance the user experience

Predictive loading

Implementing intelligent loading solutions that pre-fetch content as the user approaches the end can greatly enhance the user experience.

Utilise modern APIs

Consider the Intersection Observer API for detecting the presence of an element in the viewport. This modern approach can be more efficient than traditional scroll event listeners and helps avoid complications with dynamic heights.