DEV Community

Cover image for Learn How to Build Responsive Navigation Bar with HTML, CSS, and JavaScript
David Bilson
David Bilson

Posted on • Edited on

Learn How to Build Responsive Navigation Bar with HTML, CSS, and JavaScript

A responsive navigation bar is essential for any web application, whether you are building static websites using the frontend trio (HTML, CSS, JS) or technologies such as React and Angular for single-page apps, it is crucial to know how to build a well-designed navigation bar.

This step-by-step tutorial will give you a clean walk-through, and a straightforward approach to building a responsive navigation bar that adapts to different screen sizes and provides a clean browsing experience for your users.

If you are a beginner, it is important to understand that when building with HTML, it is advisable to avoid using div containers excessively. Instead, you should adopt a semantic approach.

To ensure clarity, let's break down the entire tutorial into a series of steps.

Step 1 (HTML structure)

Create the complete HTML structure.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Navigation Bar</title>
</head>
<body>

</body>
</html>
Enter fullscreen mode Exit fullscreen mode

Remember, all the content of a web page is enclosed within the <body> element. Therefore, we will begin by nesting a <header> element within the <body> element. This <header> element will be the parent container for the <nav> element.

Step 2 (Create header and nav element)

Create a <header> element within the body and assign it a class name of "navigation-header". Next, nest a <nav> element within the <header>. Inside the <nav>, include two <div> containers.
The first div, with a class name of "logo-container", will contain the logo, while the second div, with a class name of "navigation-items" will contain the navigation items. Also, give the navigation items container an id of "navigation-items".

Nest <a></a> within the logo container, the content of the anchor tag can either be text or an image, depending on the requirement of your project.
Nest three <a></a> within the navigation items container. The text content of each anchor element will be based on the requirements of your project. For the sake of this tutorial, I will use "About", "Projects", and "Contact Me" as the text contents for each anchor element respectively.

Lastly, for the HTML part of this tutorial, you will nest another div container within the nav element. This container will host the hamburger icons that will be displayed on smaller screens. Give it a class name of "hamburger". Then, nest two spans within it. The first span should have an id of "openHam" with a hamburger HTML entity as its text content &#9776;. The second span should have an id of "closeHam" with a HTML entity &#x2716; as its text content.

Complete HTML Code Snippet

 <header class="navigation-header">
    <nav>
        <div class="logo-container">
            <a href="./index.html">Logo</a>
        </div>
        <div class="navigation-items" id="navigation-items">
            <a href="">About</a>
            <a href="">Projects</a>
            <a href="">Contact Me</a>
        </div>
        <div class="hamburger">
            <span id="openHam">&#9776;</span>
            <span id="closeHam">&#x2716;</span>
        </div>
    </nav>
   </header>
Enter fullscreen mode Exit fullscreen mode

Step 3 (Styling with CSS)

Before proceeding to styling the HTML elements in the external CSS file, ensure the CSS file is attached to the HTML file within the head element using the tag.

<link rel="stylesheet" href="style.css">
Enter fullscreen mode Exit fullscreen mode

It is a common practice in web development to apply a CSS reset or CSS normalization to ensure a consistent starting point for styling across different browsers. By resetting the padding, margin, and box-sizing properties of all elements, as well as the body element, you can avoid any inconsistencies or unexpected default styles that different browsers may apply.

- Create a consistent styling foundation

*, body {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
}
Enter fullscreen mode Exit fullscreen mode

The CSS snippet above helps to create a more predictable layout and styling behavior across different browsers and devices.

Style the navigation header

Select the header element using its class name. Since it is the parent container for the <nav>, it is going to be the main background, and would have a definite height.
The navigation element within it should be centered on the x-axis and y-axis, therefore, flex properties come into play.

.navigation-header {
  background-color: rgb(73, 51, 153);
  padding: 0 15px;
  height: 60px;
  display: flex;
  justify-content: center;
  align-items: center;
}
Enter fullscreen mode Exit fullscreen mode

Style the nav

Since we are working with only one <nav> element, we do not need to give it a class name. Select the nav element using its element name.
If the project you are working requires a uniform width on all parent containers, then you are going to set the max-width of the nav to that required max-width of your project.

For the sake of this project, we are going to set the max-width to 1200px. To make the container stretch to the full max-width, apply 100% width. This way, the container stretches up to the max-width but won't exceed the maximum width making the container responsive in that process.
There are three child containers within the nav, they need to be on the same plain on the x-axis, therefore, we are going to make use of the flex properties to space out the containers and align them properly using the snippet below.

nav {
  width: 100%;
  max-width: 1200px;
  display: flex;
  justify-content: space-between;
  align-items: center;
}
Enter fullscreen mode Exit fullscreen mode

Style the logo

Select the anchor element within the logo container. Set its text color to ghostwhite. Remove any underlining or decoration from the text within the <a> element. Set the font-weight to bold (700 is the numeric value for bold font-weight). Set the font-size to 26 pixels.

.logo-container > a {
  color: ghostwhite;
  text-decoration: none;
  font-weight: 700;
  font-size: 26px;
}
Enter fullscreen mode Exit fullscreen mode

Style the navigation items

Select the navigation items using its class name. Within the navigation items, we have three navigation links, make them align horizontally using the flex layout.

.navigation-items {
  display: flex;
  gap: 40px;
}
Enter fullscreen mode Exit fullscreen mode

Style the navigation links

Select the links within the navigation items using the direction child selector. Set the text color to "ghostwhite", remove text decoration, apply a font weight of 500, and set the font size to 16 pixels. Also add a transition for smooth hover effect.

.navigation-items > a {
  color: ghostwhite;
  text-decoration: none;
  font-weight: 500;
  font-size: 16px;
  transition: .4s ease-in-out;
}
Enter fullscreen mode Exit fullscreen mode

Add hover effect to navigation links

Simply change the color of the navigation to white, or based on the requirement of your project.

.navigation-items > a:hover {
  color: white;
}
Enter fullscreen mode Exit fullscreen mode

Style the hamburger

The hamburger has two child elements within it which includes the openHam and the closeHam icons. Here we used HTML entities for the icons, you can import icons from icon libraries such as font awesome, google fonts or iconicon library.
On desktop and laptop screens, we definitely do not want the hamburger icons to show, so we hide them by default, then make them show up on smaller screens using media queries. But we are going to add some other default styling to the hamburger.

.hamburger {
  display: none;
  font-size: 20px;
  font-weight: 800;
  color: white;
}
Enter fullscreen mode Exit fullscreen mode

We are done with the desktop version of the entire navigation. Now, let's proceed to making it responsive and well designed for the smaller screens using media query.

Create a different style for hamburger, and the navigation items on smaller screens using CSS media query

Here, we are going to have a different style from tablet devices with screen sizes from 768px below, this would also cover for mobile screens.

@media screen and (max-width:768px) { }
Enter fullscreen mode Exit fullscreen mode

Media query is commonly used for creating responsive designs that adapt to smaller screen sizes, such as tablets or smaller desktop screens.

In the above code snippet, the styles within the media query will only be applied when the screen width is 768 pixels or smaller.

Elements are reselected within the curly braces and are styled to fit properly to the current screen size as written in the media query which is 768px in this case.

The hamburger and the navigation items will be reselected and styled to fit properly for the 768px screens

@media screen and (max-width:768px) {
  .hamburger {
    display: flex;
    cursor: pointer;
  }
  .hamburger #closeHam {
    display: none;
  }
}
Enter fullscreen mode Exit fullscreen mode

The closeHam icon is hidden and should only display when the navigation menu is displayed.

Style the navigation-items within the media query

.navigation-items {
    display: none;
    flex-direction: column;
    align-items: center;
    position: absolute;
    right: 0;
    top: 58px;
    background-color: rgb(73, 51, 153);
    width: 100%;
    height: calc(100vh - 58px);
    padding-top: 60px;
    gap: 10vh;
  }
Enter fullscreen mode Exit fullscreen mode

It is hidden by default using the display: none; property and should only show up when the openHam icon is clicked.
We are going to handle this event logic using JavaScript

Complete CSS Code

*, body {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
  font-family: sans-serif;
}

/* Navigation */
.navigation-header {
  background-color: rgb(73, 51, 153);
  padding: 0 15px;
  height: 60px;
  display: flex;
  justify-content: center;
  align-items: center;
}

nav {
  width: 100%;
  max-width: 1200px;
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.logo-container > a {
  color: ghostwhite;
  text-decoration: none;
  font-weight: 700;
  font-size: 26px;
}
.navigation-items {
  display: flex;
  gap: 40px;
}
.navigation-items > a {
  color: ghostwhite;
  text-decoration: none;
  font-weight: 500;
  font-size: 16px;
  transition: .4s ease-in-out;
}
.navigation-items > a:hover {
  color: white;
}
.hamburger {
  display: none;
  font-size: 20px;
  font-weight: 800;
  color: white;
}
@media screen and (max-width:768px) {
  .hamburger {
    display: flex;
    cursor: pointer;
  }
  .hamburger #closeHam {
    display: none;
  }
  .navigation-items {
    display: none;
    flex-direction: column;
    align-items: center;
    position: absolute;
    right: 0;
    top: 58px;
    background-color: rgb(73, 51, 153);
    width: 100%;
    height: calc(100vh - 58px);
    padding-top: 60px;
    gap: 10vh;
  }
}
Enter fullscreen mode Exit fullscreen mode

Step 4 Click event logic with JavaScript

Variables for openHam, closeHam and navigationItems

Create openHam, closeHam, and navigationItems variables and assign to elements in the HTML document using their corresponding IDs.

let openHam = document.querySelector('#openHam');
let closeHam = document.querySelector('#closeHam');
let navigationItems = document.querySelector('#navigation-items');
Enter fullscreen mode Exit fullscreen mode

Create a reusable function that controls visibility of elements.

const hamburgerEvent = (navigation, close, open) => {
    navigationItems.style.display = navigation;
    closeHam.style.display = close;
    openHam.style.display = open;
};
Enter fullscreen mode Exit fullscreen mode

The code snippet defines a function called hamburgerEvent which takes three parameters: navigation, close, and open. Inside the function, it modifies the CSS display property of the navigationItems, closeHam, and openHam elements based on the provided values.

Using an event listener, attach a click event to openHam and closeHam icons, with the hamburgerEvent function as the second parameter of the event listener:

openHam.addEventListener('click', () => hamburgerEvent("flex", "block", "none"));
closeHam.addEventListener('click', () => hamburgerEvent("none", "none", "block"));
Enter fullscreen mode Exit fullscreen mode

openHam.addEventListener('click', () => hamburgerEvent("flex", "block", "none")); sets up an event listener for the click event on the openHam icon.

When this element is clicked, it triggers an anonymous arrow function that calls the hamburgerEvent function with the arguments "flex", "block", and "none". This will change the display property of navigationItems to "flex", closeHam to "block", and openHam to "none", effectively showing the navigation items and switching the hamburger icon to the close icon.

The event listener attached to the closeHam does the exact opposite of this by passing "none", "none", "block" as the parameters of the hamburgerEvent function invoked in the event listener.

Complete JavaScript Code

let openHam = document.querySelector('#openHam');
let closeHam = document.querySelector('#closeHam');
let navigationItems = document.querySelector('#navigation-items');

const hamburgerEvent = (navigation, close, open) => {
    navigationItems.style.display = navigation;
    closeHam.style.display = close;
    openHam.style.display = open;
};

openHam.addEventListener('click', () => hamburgerEvent("flex", "block", "none"));
closeHam.addEventListener('click', () => hamburgerEvent("none", "none", "block"));
Enter fullscreen mode Exit fullscreen mode

Top comments (1)

Collapse
 
quantotius profile image
quantotius

I created a similar menu using media queries, optimized for a solitaire game, but instead of adding a hamburger option, I made the menu items more "rectanglish", so in the end easier to tap on mobiles.