Scroll to top JavaScript

A button to return to the top of the page allows the user to quickly return to the top of the page without making too much effort. This can be very useful when the page has a lot of content or which happens, for example, on one page websites, when infinite scrolling is used, or on mobile devices where different screen sizes can cause the content to scroll extend.

Those buttons usually float in the bottom corner of sites and then take you back to the top of the page when clicked. They are pretty easy to create with JavaScript. But visually, we are looking for it to be non-obtrusive while still being a large enough target to tap or click. Lets look at a few ways we can do this, starting simple, then improving things as we go.

Option 1: Keep it simple

First, we select the button in JavaScript.

var scrollToTopBtn = document.getElementById["scrollToTopBtn"]

Now document.documentElement returns the root element of the document. We need it to get the offset values. So, next lets save it in a variable called rootElement that way its easier to call in the code.

var rootElement = document.documentElement

Well add a click event listener to the button:

function scrollToTop { // scroll to top logic } scrollToTopBtn.addEventListener["click", scrollToTop]

Then, inside the scrollToTop function, we will make it scroll to the top of the screen with the scrollTo method.

function scrollToTop[] { // Scroll to top logic rootElement.scrollTo[{ top: 0, behavior: "smooth" }] }

We can style the button up a bit as well:

#scrollToTopBtn { background-color: black; border: none; border-radius: 50%; color: white; cursor: pointer; font-size: 16px; line-height: 48px; width: 48px; }

Now were able to drop the button somewhere down the page, say, the footer:

And we get this:

CodePen Embed Fallback

Option 2: Detecting the scroll position

We can detect scrolling with a scroll event listener.

function handleScroll[] { // Do something on scroll } document.addEventListener["scroll", handleScroll]

The handleScroll function will be called every time the user scrolls. Now we need the total number of pixels we can scroll.

  • scrollHeight gives the height of an element, including the part not visible due to overflow.
  • clientHeight gives the inner height of an element in pixels, which is the height of the visible part.

If we subtract scrollHeight by clientHeight, we get the total amount of pixels that we can scroll:

var scrollTotal = rootElement.scrollHeight - rootElement.clientHeight

Now we have a variable called scrollTotal that represents the maximum number of pixels that can be scrolled vertically. By dividing the amount scrolled by the total amount of pixels we can scroll, we get a ratio between 0 and 1. Playing with this ratio, we can easily toggle the button on and off.

For example, we will add a condition that shows the scroll-to-top button when the user has scrolled 80%, [or a ratio of 0.80] down the total height of the page. 80% is an arbitrary number. Basically, the closer we get to 1, the more the user has to scroll before seeing the button.

Heres the JavaScript:

var rootElement = document.documentElement function handleScroll[] { // Do something on scroll var scrollTotal = rootElement.scrollHeight - rootElement.clientHeight if [[rootElement.scrollTop / scrollTotal ] > 0.80 ] { // Show button scrollToTopBtn.classList.add["showBtn"] } else { // Hide button scrollToTopBtn.classList.remove["showBtn"] } } document.addEventListener["scroll", handleScroll]

Were going to want some CSS to position the button correctly when it comes into view:

.scrollToTopBtn { /* same general styles as before */ /* place it at the bottom-right corner */ position: fixed; bottom: 30px; right: 30px; /* keep it at the top of everything else */ z-index: 100; /* hide with opacity */ opacity: 0; /* also add a translate effect */ transform: translateY[100px]; /* and a transition */ transition: all .5s ease } .showBtn { opacity: 1; transform: translateY[0] }

With that, the button appears when the user gets 80% down the page and then hides when its higher than that.

CodePen Embed Fallback

This seems like a grand option, and setting an event listener to do this is pretty easy. But the performance overhead can be costly since were always checking the current scroll position.

Theres another option that takes care of this

Option 3: Intersection Observer

The Intersection Observer API is an excellent solution to the above problem. Its a fairly recent browser API that lets developers hand most of these tasks off to the browser, in a way that is more optimized. Travis Almand wrote up a thorough explanation of how it works. Heres how MDN defines it:

The Intersection Observer API provides a way to asynchronously observe changes for the intersection of a target element with an ancestor element or with a top-level documents viewport.

Pretty neat! That means the button can be our target element:

// We select the element we want to target var target = document.querySelector["footer"];

We then write a callback function that does something when our element becomes intersects with the viewport which is a fancy way of saying when it comes into view.

And once the footer enters or leaves the viewport, all we really want to do is add or remove a class. The callback receives an array of entries as a parameter.

function callback[entries, observer] { // The callback will return an array of entries, even if you are only observing a single item entries.forEach[entry => { if [entry.isIntersecting] { // Show button scrollToTopBtn.classList.add['showBtn'] } else { // Hide button scrollToTopBtn.classList.remove['showBtn'] } }]; }

We need to create a new IntersectionObserver instance and pass it the callback function we just wrote.

let observer = new IntersectionObserver[callback];

Finally, we tell the observer to start watching [err, observing] the target element that was selected above for when it intersects with the viewport:

observer.observe[target];
CodePen Embed Fallback

And what about smooth scrolling?

Of course its possible! In fact, Chris showed us how it can be done with CSS back in 2019:

Jump to top of page html { scroll-behavior: smooth; }

Theres a little more nuance to there, like accessibility enhancements that Chris also covers in the post. The point is that CSS is gaining new powers that can accomplish things that we used to use JavaScript for.

There you have it! We started with a pretty simple idea. We enhanced it by displaying and hiding the button based on the users scroll position. Then we improved the performance by implementing the Intersection Observer API instead of watching the current scroll position. And, finally, we saw how CSS can be used for smooth scrolling. All together, we get a scroll-to-top button that is easy to see and use, while not blocking other elements on the page.

Video liên quan

Chủ Đề