Andrew
Walpole

Principal Web
Developer &
Engineering
Manager

Designer
Leader
Teacher
Learner
Maker

The Showy / Hidey Navigation Bar

That’s definitely the technical term for it. It’s that popular navbar pattern where the header disappears above the screen as you scroll down, affording you more content consumption space, but then, as if it were waiting just out of view for you, reappears upon the slightest scroll up.

I’ve built so many of these over the last few years, I decided to distill the pattern down. Essentially we need just a few ingredients to pull it off:

For our html:

<header>
  <div class="navbar">
    <!-- All the nav stuff-->
  </div>
</header>

Focusing just on the pattern, I’ve left the innards of the navbar up to you, maybe a logo and a list of links would be good. We really just need the extra .navbar class to position: fixed; while the <header> stays position: static; to hold the space for the navbar. You can see that in our CSS:

header {
  --nav-height: 100px;
  min-height: var(--nav-height);
  
  .navbar {
    --top-position: 0px;
    position:fixed;
    width:100%;
    top: var(--top-position);
    
    transition: top 0.6s;
    
    &.hide:not(:focus-within) {
      --top-position: -100%;
    }
  }
}

As I mentioned, setting the --nav-height is important because without letting the component know how tall it might be, it can’t hold any space at the top of the page for the navbar to sit into. So either your first content section will run under the navbar, or if you toggle it between static and fixed positioning when you scroll, it will jump the screen up as it’s taken out of the flow. It’s all much simpler if you just hold the right amount of pixel space.

Next, we default the top to 0px and change it to -100% when it has the .hide class applied. Add in a transition and your navbar is ready to hide and show elegantly.

It’s also worth mentioning the :not(:focus-within) bit, which allows the navbar to not be hidden when we give focus to the nav items. So as you tab through with a keyboard, the navbar will reappear.

Finally, we need some javascript to hook it all together. Though when scroll-driven animations are widely available, perhaps we won’t need that at all.

const useShowyHidey = () => {
  let lastScrollTop = 0;
  const navbar = document.querySelector(".navbar");
  
  const toggleNavOnScroll = () => {
    const st = document.documentElement.scrollTop;
    if ( st > lastScrollTop && st > parseInt(getComputedStyle(navbar).getPropertyValue("--nav-height")) ) {
      navbar.classList.add("hide");
    } else if (st < lastScrollTop) {
      navbar.classList.remove("hide");
    }
    lastScrollTop = st <= 0 ? 0 : st;
  }
  
  if (navbar) {
    window.removeEventListener( "scroll", toggleNavOnScroll);
    window.addEventListener( "scroll", toggleNavOnScroll);
  }
}

useShowyHidey();

We listen to the scroll event and toggle the .hide class based on scroll direction.

And here’s the whole thing in a codepen!

See the Pen Showy / Hidey Navigation Bar by Andrew (@walpolea) on CodePen.