loading...

How to create full-screen drawer navigation in HTML, CSS, and JavaScript

khwilo profile image Khwilo Kabaka Updated on ・7 min read

Introduction

In this guide, we are going to learn how to create a navigation menu that overlays other elements on a page. We will layout the structure of the page first using HTML, add styling using CSS and then add interactivity (opening and closing of the navigation drawer) using JavaScript. Let's get started.

Document Structure

First, we will add the structure of the page. In the body tag of your HTML, add the header contents as follows:

<header class="header">
  <div class="logo">
    <h1 class="logo__text">Logo</h1>
  </div>
  <button class="menu-toggle" aria-label="Menu toggle button">
    <span class="hamburger"></span>
  </button>
  <nav class="nav">
    <ul class="nav__list">
      <li class="nav__list-item">
        <a href="#home" class="nav__link">Home</a>
      </li>
      <li class="nav__list-item">
        <a href="#about" class="nav__link">About</a>
      </li>
      <li class="nav__list-item">
        <a href="#projects" class="nav__link">Project</a>
      </li>
      <li class="nav__list-item">
        <a href="#contact" class="nav__link">Contact</a>
      </li>
    </ul>
  </nav>
</header>

The header content has a logo, a button representing the hamburger menu and navigation links. Since the button element doesn't contain any text, it's important to add an aria-label associated with it.

The remaining structure will be the main content where one has to navigate to:

<main class="main">
  <div class="main__home" id="home">
    <h2 class="main__section-title">Home</h2>
    <p class="main__section-content">
      Lorem ipsum dolor sit, amet consectetur adipisicing elit. Officia 
      magnam quod iure ex unde reiciendis adipisci sint saepe nam nostrum 
      quibusdam sit, possimus nihil expedita. Consequatur, consequuntur 
      sint. Necessitatibus, recusandae? Lorem ipsum dolor sit, amet 
      consectetur adipisicing elit. Asperiores, dolorum! Atque, nam vitae 
      qui ab commodi ullam. Mollitia expedita a quae fugit obcaecati nam 
      amet possimus magni natus, sequi vitae. Lorem ipsum, dolor sit amet 
      consectetur adipisicing elit. Possimus, nobis consectetur alias odit 
      laboriosam fugiat voluptas, molestias vitae itaque excepturi 
      perferendis necessitatibus consequuntur deleniti. Quas incidunt 
      officia provident reiciendis sed!
    </p>
  </div>
  <div class="main__about" id="about">
    <h2 class="main__section-title">About</h2>
    <p class="main__section-content">
      Lorem ipsum dolor sit, amet consectetur adipisicing elit. Officia 
      magnam quod iure ex unde reiciendis adipisci sint saepe nam nostrum 
      quibusdam sit, possimus nihil expedita. Consequatur, consequuntur 
      sint. Necessitatibus, recusandae? Lorem ipsum dolor sit, amet 
      consectetur adipisicing elit. Asperiores, dolorum! Atque, nam vitae 
      qui ab commodi ullam. Mollitia expedita a quae fugit obcaecati nam 
      amet possimus magni natus, sequi vitae. Lorem ipsum, dolor sit amet 
      consectetur adipisicing elit. Possimus, nobis consectetur alias odit 
      laboriosam fugiat voluptas, molestias vitae itaque excepturi 
      perferendis necessitatibus consequuntur deleniti. Quas incidunt 
      officia provident reiciendis sed!
    </p>
  </div>
 <div class="main__projects" id="projects">
    <h2 class="main__section-title">Projects</h2>
    <p class="main__section-content">
      Lorem ipsum dolor sit, amet consectetur adipisicing elit. Officia 
      magnam quod iure ex unde reiciendis adipisci sint saepe nam nostrum 
      quibusdam sit, possimus nihil expedita. Consequatur, consequuntur 
      sint. Necessitatibus, recusandae? Lorem ipsum dolor sit, amet 
      consectetur adipisicing elit. Asperiores, dolorum! Atque, nam vitae 
      qui ab commodi ullam. Mollitia expedita a quae fugit obcaecati nam 
      amet possimus magni natus, sequi vitae. Lorem ipsum, dolor sit amet 
      consectetur adipisicing elit. Possimus, nobis consectetur alias odit 
      laboriosam fugiat voluptas, molestias vitae itaque excepturi 
      perferendis necessitatibus consequuntur deleniti. Quas incidunt 
      officia provident reiciendis sed!
    </p>
 </div>
 <div class="main__contact" id="contact">
     <h2 class="main__section-title">Contact</h2>
    <p class="main__section-content">
      Lorem ipsum dolor sit, amet consectetur adipisicing elit. Officia 
      magnam quod iure ex unde reiciendis adipisci sint saepe nam nostrum 
      quibusdam sit, possimus nihil expedita. Consequatur, consequuntur 
      sint. Necessitatibus, recusandae? Lorem ipsum dolor sit, amet 
      consectetur adipisicing elit. Asperiores, dolorum! Atque, nam vitae 
      qui ab commodi ullam. Mollitia expedita a quae fugit obcaecati nam 
      amet possimus magni natus, sequi vitae. Lorem ipsum, dolor sit amet 
      consectetur adipisicing elit. Possimus, nobis consectetur alias odit 
      laboriosam fugiat voluptas, molestias vitae itaque excepturi 
      perferendis necessitatibus consequuntur deleniti. Quas incidunt 
      officia provident reiciendis sed!
    </p>
 </div>
</main>

The main content contains navigation target elements having a stub text.

Styling the contents

Now will be the time to add style to the contents. First, we will add some basic styling:

@import url('https://fonts.googleapis.com/cssfamily=Lato:400,700|Pacifico&display=swap');

:root {
  font-size: calc(0.5em + 1vw);

  --clr-cream: #f6e7c1;
  --clr-light-orange: #ffa25b;
  --clr-orange: #f4722b;
  --clr-dark: #3e3e3e;
  --clr-white: #fff;

  --fw-regular: 400;
  --fw-bold: 700;

  --fs-heading-1: 3em;
  --fs-heading-2: 1.5em;
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

body {
  background-color: var(--clr-cream);
  color: var(--clr-dark);
  font-family: 'Lato', sans-serif;
  margin: 0;
}

h1 {
  margin: 0;
}

.logo__text {
  font-family: 'Pacifico', cursive;
  font-size: var(--fs-heading-1);
  color: var(--clr-orange);
}

The above code snippet adds a responsive font, the font families to use and also adds a color palette. To distinguish the main content details, add the following styling:

.main {
  width: 80%;
  margin: 0 auto;
}

.main > * { /* Target direct descendants of the .main class */
  padding: 1em;
}

.main > * + * { /* Target adjacent direct descendants of the .main class */
  margin-top: 1em;
}

.main > *:nth-child(odd) { /* Targets the odd children of the .main class */
  background-color: var(--clr-dark);
}

.main__section-title { /* Section heading */
  font-size: var(--fs-heading-2);
  color: var(--clr-light-orange);
  margin: 0;
  padding: 0;
  display: inline;
  text-decoration: underline;
}

.main__section-content { /* Section content */
  padding: 0;
  margin-top: 0.5em;
}

.main > *:nth-child(odd) > .main__section-title { /* Odd main element child heading */
  background-color: var(--clr-dark);
}

.main > *:nth-child(odd) > .main__section-content { /* Odd main element child content */
  background-color: var(--clr-dark);
  color: var(--clr-white);
}

Style the navigation drawer

Make the header element have a display of flex and let the navigation element position be fixed and bring it to the front by declaring a z-index of 1.

.header {
  display: flex;
  justify-content: space-between;
  padding: 1em;
}

.nav {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  background-color: var(--clr-dark);
  z-index: 1;
}

Style the navigation item list by removing the default style type for list items and centering the items on the page. Adding a margin 0 ensures that the background color covers the entire page.

.nav__list {
  list-style-type: none;
  padding: 0;
  display: flex;
  flex-direction: column;
  justify-content: space-around;
  align-items: center;
  height: 100%;
  background-color: var(--clr-dark);
  margin: 0;
}

To make the navigation links visible, we are going to make them have a white color and a font-size of 1.5em. When a user hovers over the links, make the links to have a color of light orange and underline the text. On focus, the links will have an orange color:

.nav__link {
  text-decoration: none;
  padding: 1em 2em;
  background-color: var(--clr-dark);
  color: var(--clr-white);
  font-size: var(--fs-heading-2);
  font-weight: var(--fw-bold);
  padding: 0;
  margin: 0;
}

.nav__link:hover {
  text-decoration: underline;
  color: var(--clr-light-orange);
}

.nav__link:focus {
  color: var(--clr-orange);
}

We are then going to add a hamburger menu using CSS. Position the button element to the top right of the page. Bring it to the front by adding a z-index of 2. Add a background of transparent and remove its border:

.menu-toggle {
  padding: 1.5em;
  background: transparent;
  border: none;
  cursor: pointer;
  position: absolute;
  top: 1em;
  right: 1em;
  z-index: 2;
}

The hamburger is wrapped inside a span in the button element. The span is displayed as a block element. Declare a relative position to the span since we are going to add 3 horizontal bars to it.

.hamburger {
  display: block;
  position: relative;
}

Declare the width, height and background color of the horizontal bars:

.hamburger,
.hamburger::before,
.hamburger::after {
  width: 2.5em;
  height: 2px;
  background-color: var(--clr-orange);
}

The pseudo-elements :before and :after of the .hamburger class represents the bottom and top horizontal bars.

For the to bottom and top horizontal bars, let them have an absolute positioning with a left and right of zero.

.hamburger::before,
.hamburger::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
}

Move the bottom horizontal bar 8px from the top and the top horizontal bar to be 8px from the bottom of the middle horizontal bar.

.hamburger::before {
  top: 8px;
}

.hamburger::after {
  bottom: 8px;
}

Add interactivity

Hide the navigation drawer by moving it further to the right along the x-axis.

.nav {
  transform: translateX(100%);
}

Get the reference of the toggle menu button using JavaScript and add a class of nav-open to the body when the button is clicked.

const toggleMenu = document.querySelector('.menu-toggle');

toggleMenu.addEventListener('click', () => {
  document.body.classList.toggle('nav-open');
});

When the navigation drawer is open, we display the navigation menu by moving it to the view using CSS. Then, have the menu toggle button to be fixed to the top when scrolling.

.nav-open .nav {
  transform: translate(0);
} 

.nav-open .menu-toggle {
  position: fixed;
}

Change the hamburger menu to an X character by rotating the horizontal bars. The hamburger menu is rotated to 45 degrees. The bottom horizontal bar is rotated to 90 degrees and then is aligned by moving it 8px away from the x-axis so that the X character is displayed. This because we declared it to be 8px from the top. The top horizontal bar is set to have an opacity of zero.

.nav-open .hamburger {
  transform: rotate(45deg);
}

.nav-open .hamburger::before {
  transform: rotate(90deg) translateX(-8px);
}

.nav-open .hamburger::after {
  opacity: 0;
}

Currently, when clicking the navigation links the URL changes but we are not being taken to the desired section. To do so, we need to remove the class nav_open from the body when the links are clicked as follows:

const navigationLinks = document.querySelectorAll('.nav__link');

navigationLinks.forEach(link => {
  link.addEventListener('click', () => {
    document.body.classList.remove('nav-open');
  });
});

All navigation links references are fetched from the document then we loop over each link and remove the class nav-open when a link is clicked.

Now the navigation drawer is fully functional.

Bonus

We are going to add simple animation for good user experience. When scrolling, instead of a straight jump to an individual item, make the scroll behavior appear to be gradual. The navigation slides in from the left when the hamburger menu is clicked. The hamburger transitions to an X by accelerating on easing in and decelerates on easing out.

html {
  scroll-behavior: smooth;
}

.nav {
  transition: transform 300ms cubic-bezier(0.785, 0.135, 0.15, 0.86);
}

.hamburger::before,
.hamburger::after {
  transition: transform 300ms ease-in-out;
}

The source code of the application can be found here https://github.com/khwilo/drawer-navigation. Access the live site using the link https://drawer-navigation.netlify.com/.

Posted on by:

khwilo profile

Khwilo Kabaka

@khwilo

Mobile web application developer skilled in developing mobile web applications that utilize the capabilities and features of the modern web.

Discussion

pic
Editor guide