auto hiding menu

Create auto-hiding navigation menu with Vanilla Javascript

You can do many things with JQuery. Do you ever think about you should convert JQuery program to Vanilla Javascript? You should do it. Why? The vanilla Javascript concept means pure Javascript without any frameworks. So, almost browsers support Vanilla JS. Because Vanilla JS is a native language for browsers, so it runs faster than other Javascript frameworks, such as JQuery.

Today, I will show you how to make a cool menu with Vanilla JS. This menu will appear if you scroll up and hide if you scroll down.

Design html page

First, you need to design an html page (index.html) and set the following code in body tag:

<div class="container">
  <div class="banner-wrapper">
    <div class="banner">
      <div class="top">
        <!-- Navbar top row-->
      </div>
      <div class="nav">
        <!-- Links for navigation-->
      </div>
    </div>
  </div>

  <div class="content">
    <!-- Awesome content here -->
  </div>
</div>

Above code is very basical. You use a container div to hold allthing. Inside it, you have banner-wrapper and content divs. Inside banner-wrapper, you insert a banner div. And inside banner div, you have the top div and nav div.

Style DOM by CSS

Now we will style DOM. You can use the following CSS:

*{
  box-sizing:border-box;
  padding: 0;
  margin: 0;
}

.container{
  width: 100%;
}

.banner-wrapper {
  z-index: 4;
  transition: all 300ms ease-in-out;
  position: fixed;
  width: 100%;
}

.banner {
  height: 77px;
  display: flex;
  flex-direction: column;
  justify-content: space-around;
  background: rgba(162, 197, 35, 1);
  transition: all 300ms ease-in-out;
}

.content {
  background: url(https://unsplash.it/1400/1400?image=699) center no-repeat;
  background-size: cover;
  padding-top: 100%;
}

There are some CSS properties that you need to notice:
* box-sizing: The box-sizing property is used to tell the browser what the sizing properties (width and height) should include. Should they include the border-box? Or just the content-box (which is the default value of the width and height properties)?
* z-index: The z-index property specifies the stack order of an element. An element with greater stack order is always in front of an element with a lower stack order. The z-index only works on positioned elements (position:absolute, position:relative, or position:fixed).
* transition: CSS3 transitions allows you to change property values smoothly (from one value to another), over a given duration. You can read more about transition at W3C.
* display: specifies the type of box used for an element. Flexible boxes, or flexbox, is a new layout mode in CSS3. Use of flexbox ensures that elements behave predictably when the page layout must accommodate different screen sizes and different display devices. For many applications, the flexible box model provides an improvement over the block model in that it does not use floats, nor do the flex container’s margins collapse with the margins of its contents.
* flex-direction: The flex-direction CSS property specifies how flex items are placed in the flex container defining the main axis and the direction (normal or reversed).The value column means that the flex container’s main-axis is the same as the block-axis. The main-start and main-end points are the same as the before and after points of the writing-mode.
* justify-content: defines how the browser distributes space between and around content items along the main axis of their container. The space-around value means the items are evenly distributed within the alignment container along the main axis. The spacing between each pair of adjacent items is the same. The empty space before the first and after the last item equals half of the space between each pair of adjacent items.
* background: set background for element. Background can be filled by color, image, gradient. You can read more about background property at Mozilla.
* background-size: The background-size CSS property specifies the size of the background images. The size of the image can be fully constrained or only partially in order to preserve its intrinsic ratio. The cover value means that scales the image as large as possible and maintains image aspect ratio (image doesn’t get squished). The image “covers” the entire width or height of the container. When the image and container have different dimensions, the image is clipped either left/right or top/bottom.

Write Vanilla JS to make animated menu

The first thing we need to do is to attach an event handler to the scroll event, so that we can show and hide the menu accordingly when the user scrolls. We’ll also enclose everything in an IIFE so as to avoid clashes with other code running on the same page.

(() => {
  'use strict';

  const handler = () => {
    //DOM manipulation code here
  };

  window.addEventListener('scroll', handler, false);
})();

Setting Some Initial Values
We’ll be using a refOffset variable to represent the amount of distance the user has scrolled down the page. This is initialized to 0 on page load. We’ll use a bannerHeight variable to store the menu’s height and will also need references to the .banner-wrapper and .banner DOM elements.

let refOffset = 0;
let visible = true;
const bannerHeight = 77;

const bannerWrapper = document.querySelector('.banner-wrapper');
const banner = document.querySelector('.banner');

Establishing Scroll Direction
Next we need to establish scroll direction so that we can show or hide the menu accordingly.

We’ll start off with a variable called newOffset. On page load this will be set to the value of window.scrollY — the number of pixels that the document is currently scrolled vertically (so 0 initially). When a user scrolls, newOffset will increase or decrease accordingly. If it is greater than the value stored in bannerHeight then we know our menu has been scrolled out of view.

const newOffset = window.scrollY;

if (newOffset > bannerHeight) {
  // Menu out of view
} else {
  // Menu in view
}

Scrolling down will make newOffset greater than refOffset and the navigation menu should slide up and disappear. Scrolling up will make newOffset less than refOffset and the navigation menu should slide back into view with a see through effect. After performing this comparison, we will need update refOffset with the value of newOffset to keep track of how far the user has scrolled.

if (newOffset > bannerHeight) {
  // Menu out of view
  if(newOffset > refOffset) {
    // Hide the menu
  } else if (newOffset < refOffset) {
    // Slide menu back down
  }

  refOffset = newOffset;
} else {
  // Menu in view
}

Animating the Menu

Finally, let’s add an animateIn and an animateOut method to show and hide the menu. We should also make sure that the see-through effect is removed from the menu once the top of page is reached.

if (newOffset > bannerHeight) {
  if (newOffset > refOffset) {
    animateOut();
  } else {
    animateIn();
  }

  refOffset = newOffset;
} else {
  banner.style.backgroundColor = 'rgba(162, 197, 35, 1)';
}
And here are the functions that do the animation.

function animateOut() {
  bannerWrapper.style.transform = `translateY(-${bannerHeight}px)`;
  bannerWrapper.style.msTransform = `translateY(-${bannerHeight}px)`;
  bannerWrapper.style.webkitTransform = `translateY(-${bannerHeight}px)`;
  bannerWrapper.style.MozTransform = `translateY(-${bannerHeight}px)`;
  banner.style.background = 'rgba(162, 197, 35, 0.6)';
}

function animateIn() {
  bannerWrapper.style.transform = 'translateY(0px)';
  bannerWrapper.style.msTransform = 'translateY(0px)';
  bannerWrapper.style.webkitTransform = 'translateY(0px)';
  bannerWrapper.style.MozTransform = 'translateY(0px)';
  banner.style.background = 'rgba(162, 197, 35, 0.6)';
}

You might want to consider using a CSS class for this, which you could remove and apply accordingly. In this case however, I have gone with the JavaScript version.
(This post references a note of Albert Senghor on sitepoint).