· js targeting · 5 min read

How to show and hide elements on page scroll

Share:

Creative people can often create design rules that... complicate the life of a developer. Everything from overlapping elements to odd shapes at different screen sizes. Even showing or hiding elements based on where you are at on the page and which direction you are scrolling. This last feature is something I want to talk about today.

Creative people can often create design rules that… complicate the life of a developer. Everything from overlapping elements to odd shapes at different screen sizes. Even showing or hiding elements based on where you are at on the page and which direction you are scrolling. This last feature is something I want to talk about today.

Recently, I was asked to create a feature where, on mobile sizes, the sticky header disappears and a sticky button bar shows up. But only when scrolling down. When scrolling back up the inverse should happen where we show the sticky header and hide the sticky button bar.

Where to start

First, we need to start by having two elements we want to show and hide depending on the scroll position and direction. For this I created a very simple page structure.

<div class="page">
  <div class="header">
    Header Links
  </div>

  <main class="my-site">
    <div>Main site content area.</div>
  </main>

  <div class="footer">
    Footer Container
  </div>

  <div id="sticky-buttons">
    <div class="container">
      <button class="btn">My Sticky Footer Button</button>
    </div>
  </div>
</div>

Next, I am going to assume you already have these elements styled the way you want them to show up. So instead of providing you CSS here I am going to move directly to the JavaScript part of this. If you want to see the full example, please see the bottom of this article.

What do we need in the JavaScript

The JavaScript needs four variables to make this work smoothly. I will explain along the way. First, we will need a header variable to hold the header element DOM. Then the stickyBtns variable to hold the element for the sticky buttons. You can target whichever elements makes sense for your project.

Next, we need to know the header height. We do that by using the getBoundingClientRect() function on the header element and then accessing the “height” property. Which gives us code like this.

const headerHeight = header.getBoundingClientRect().height;

Finally, we need two more variables to limit when we take action and to track where we have been. This is the delta, which is a limit we set on how far we scroll before we take action between the last scroll point and the new one. And the lastScrollTop meaning the last position from the top that we have scrolled to.

With the delta, I introduced this feature to make sure that as we are scrolling up and down we don’t see any strange jitteriness. During my initial build I had a problem where even the slightest scroll movement would cause the elements to flicker on and off. This is disorienting and created a poor user experience.

By setting the “delta” or gap between two scroll points it gives the system time to take the previous action before piling on a new action. I defaulted mine to a value of 115, which in my testing provided a nice smooth experience.

The lastScrollTop is simply a record of the most recent point we have scrolled down to. It can also be called the scroll position. This we should default to 0.

Functionality Time

Ok, you have made it this far, whew. First we will build the function we will call on scroll. Then we will set the event listener. Lets call our function hasScrolled() to indicate that we know the user has scrolled somewhere. Next, lets get the current scroll position. You do that using window.scrollY.

Which gives you:

const scrollTop = window.scrollY;

Next, we need to compare the last position to the current one. We want to subtract the new position from the previous one and take an absolute value.

Math.abs(lastScrollTop - scrollTop);

If this value is less than or equal to the delta value set then we do nothing and return out of the function.

if (Math.abs(lastScrollTop - scrollTop) <= delta) {
  return;
}

If we pass the first test, we then need to determine two more things. First, the scroll direction and second if we have scrolled past the header height. Now, why, you may ask, do we care about the header height. We care because we don’t want the header to immediately disappear. Instead, we want to make sure that as we scroll down it can stay on the screen for a moment to not disorient the user and to maintain navigation functionality.

These two tests look like this:

if (scrollTop > lastScrollTop && scrollTop > headerHeight) {
  // Scroll down action
}
else if (scrollTop < lastScrollTop) {
  // Scroll up action
}

If the current scroll position or scrollTop is greater than the previous one then we know we are scrolling down. Otherwise, we are scrolling up or are neutral.

In my code I simply added a class of “scroll-up” or “scroll-down” to the element indicate the direction and use styles to define what to do in those cases. You can define yours in the same way or provide different actions that are solely in the JavaScript itself.

After you have done these actions, we need to update the lastScrollTop position to whatever is in scrollTop.

lastScrollTop = scrollTop;

Finally, we just call the function via the event listener and away we go.

window.addEventListener('scroll', hasScrolled);

Put It All Together

To see it all put together, checkout my CodePen.

See the Pen Show/Hide Elements on Scroll by Patrick Thurmond (@pthurmond) on CodePen.

Good luck and until next time be safe, be well, and be happy!

Share: