DEV Community

Cover image for Responsive Navbar using HTML, CSS, and Javascript
Amrin
Amrin

Posted on • Edited on

Responsive Navbar using HTML, CSS, and Javascript

For every CSS project we build, a responsive navigation bar is a must-have.

So, today we are going to build a responsive navigation bar using HTML CSS and vanilla javascript.

Note: It's a Mobile-First design

If you prefer video. I also created a video. You can watch it here

Let's get started 🎉🎉

Part 1: HTML



<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="styles.css" />
    <title>responsive navbar</title>
  </head>
  <body>
    <header>
      <nav class="nav">
        <a href="/" class="logo">logo</a>

        <div class="hamburger">
          <span class="line"></span>
          <span class="line"></span>
          <span class="line"></span>
        </div>

        <div class="nav__link hide">
          <a href="#">home</a>
          <a href="#">about</a>
          <a href="#">contact</a>
          <a href="#">blog</a>
        </div>
      </nav>
    </header>
  </body>

  <script src="./script.js"></script>
</html>


Enter fullscreen mode Exit fullscreen mode

Above we got our navbar's markup with a hamburger.

I linked the CSS and javascript files too.

Let's see how we can style this markup with CSS

Part: 2 CSS



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

body {
  font-family: sans-serif;
}

a {
  text-decoration: none;
  color: black;
  font-size: 1.2rem;
  font-weight: bold;
  text-transform: uppercase;
}


Enter fullscreen mode Exit fullscreen mode

Here, we removed some of the default styles and added some styles to the a tag.



/* nav styles */

.nav {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding-top: 20px;
}

.logo {
  font-size: 1.8rem;
  color: rgb(5, 5, 116);
  padding-left: 20px;
}

.hamburger {
  padding-right: 20px;
  cursor: pointer;
}

.hamburger .line {
  display: block;
  width: 40px;
  height: 5px;
  margin-bottom: 10px;
  background-color: black;
}

.nav__link {
  position: fixed;
  width: 94%;
  top: 5rem;
  left: 18px;
  background-color: lightblue;
}

.nav__link a {
  display: block;
  text-align: center;
  padding: 10px 0;
}

.nav__link a:hover {
  background-color: lightcoral;
}

.hide {
  display: none;
}


Enter fullscreen mode Exit fullscreen mode

This is the main design. Here we styled our navbar the hamburger and the logo.

The mobile design is done.

screencapture-127-0-0-1-5500-index-html-2021-12-14-21_54_51.png

We are going to look at the desktop design now.



@media screen and (min-width: 600px) {
  .nav__link {
    display: block;
    position: static;
    width: auto;
    margin-right: 20px;
    background: none;
  }

  .nav__link a {
    display: inline-block;
    padding: 15px 20px;
  }

  .hamburger {
    display: none;
  }
}


Enter fullscreen mode Exit fullscreen mode

In the desktop design, we removed the absolute position and made it a display block.
And to the nav__link's we added display inline-block so that the links stay's next to each other.
Lastly, added display none to the .hamburger

screencapture-127-0-0-1-5500-index-html-2021-12-14-21_59_21.png

One last thing is left. Now we need to make our hamburger clickable.

Part 3 : Javascript



const hamburger = document.querySelector('.hamburger');
const navLink = document.querySelector('.nav__link');

hamburger.addEventListener('click', () => {
  navLink.classList.toggle('hide');
});



Enter fullscreen mode Exit fullscreen mode

Here we added a click event to the hamburger and added the classList.toggle to the navLink.

What the classList.toggle does is, it removes the class if the given class is available and add's if it's not available.

source code: https://github.com/Coderamrin/responsive-navbar-css-js

Live preview: https://coderamrin.github.io/responsive-navbar-css-js/

Conclusion

Thanks for reading.

If you liked it don't forget to follow me @coderamrin

also, I've started a YouTube channel where I share programming tutorials and videos. If that sounds great check it out: https://www.youtube.com/channel/UCiHUi4wJ6rkPSQ5n4bxKU1A

Have a good one :D

Top comments (17)

Collapse
 
thejourneyville profile image
benny

Thanks for this useful post! I was wondering how to setup a hamburger menu, I'll use this as a guideline. Btw I noticed a type-o:

And to the nav__link's we added display inline-block so that the links say next to each other.

Have a good one Amrin :)

Collapse
 
coderamrin profile image
Amrin

thank's for pointing it out benny :D

Collapse
 
guscarpim profile image
Gustavo Scarpim

Nice NavBar, I suggest you change your link in github is incorrect and your website.

Good job!

Collapse
 
coderamrin profile image
Amrin

thanks Gustavo.
it works now

Collapse
 
brads profile image
Bradley Oliver

naw, still broken

Thread Thread
 
coderamrin profile image
Amrin

It works for me. I don't know what's causing this

github.com/Coderamrin/responsive-n...
coderamrin.github.io/responsive-na...

Thread Thread
 
guscarpim profile image
Gustavo Scarpim

Me too

Collapse
 
tleperou profile image
Info Comment hidden by post author - thread only accessible via permalink
Thomas Lepérou

Thanks for sharing.

Being evolving in the web industry since the very early 2000's, I'd say that dealing with navigation, is tricky. A navigation fulfils critical responsibilities:

  • it designates an informational structure to users and crawlers (SEO-able)
  • it provides a way to navigate through the information (readable)
  • it presents a certain state of the information (addressable)
  • it has a way to interact with itself (usable)
  • and might be used within different platform (interoperable)

SEO-able

Delegating the most critical part of the navigation with a div > span must be avoided. Except if you have a good reason and you provide the proper aria-attributes to take over with the right DOM's semantic.

With better semantic, better structure, better opportunities for the SEO.

addressable

The state of the nav__link.hide should be bubbled up to the top level's viewport. Why? Because the display: fixed is applied to the viewport, and become a first (depth) level of reading. As a rule of thumb, always use the URL to represent the first level of reading, eg:

Thus, the state of your main navigation is addressed within the URL. Sharing a link and refreshing the page work!

usable

I consider relying on the native navigation of the browser as one of the best practice in frontend development. Updating the the URL via a link and without using JS make things sure to work, and easy to maintain over the time.

interoperable

Nowadays, frontend developers face with complexity by coding programs executed in web browsers, webworkers and backends. Adding listeners should be done carefully, cause it's tightly coupled with the DOM's rendering (browser only).

Could be something like,

  <body>
    <header>
      <a href="/">logo</a>
      <nav>
        <ul>
          <li><a href="#">home</a></li>
          <li><a href="#">about</a></li>
          <li><a href="#">contact</a></li>
          <li><a href="#">blog</a></li>
        </ul>
      </nav>
      <a href="#open-main-nav">
        <span>Toggle main navigation</span>
        <i class="burger-icon" aria-hidden="true"></i>
      </a>
    </header>
  </body>
Enter fullscreen mode Exit fullscreen mode

For the css,

// nav when open
body.main-nav-open header > nav {}

// nav by default
header > nav {}

// links on nav
header > nav a {}

// logo
header > a:first-child {}

// button to open main nav
header > a:last-child {}

// keep visible the trigger for screen reader only
header > a:last-child span {
    position: absolute !important;
    height: 1px; width: 1px;
    overflow: hidden;
    clip: rect(1px 1px 1px 1px); /* IE 7+ support */
    clip: rect(1px, 1px, 1px, 1px); /* other browsers */
}

// your own icon's implementation (fontawesome or whatever)
// CSS-based only. DOM must not be required
i.burger-icon {}

// responsiveness
@media screen and (/* your breakpoints */) {
  header > nav > ul { /* display or not */ }
}
Enter fullscreen mode Exit fullscreen mode

Finally, the JS

const toggleNavWhenLocationAsks = () => {
  const body = document.getElementsByTagName('body')[0];

  if (location.hash === '#main-nav-open') {
    return body.classList.add('main-nav-open');
  }

  return body.classList.remove('main-nav-open');
}

// toggle nav onload
// run only when window is available
window && toggleNavWhenLocationAsks();

// toggle nav on URL changes
// run only when window is available
window && window.addEventListener('hashchange', toggleNavWhenLocationAsks);
Enter fullscreen mode Exit fullscreen mode

Best

Collapse
 
raibtoffoletto profile image
Raí B. Toffoletto

I think for better a11y would be better to use a button for the hamburger and a ul/li for the navigation items. 😉 But nice work 🎉

Collapse
 
coderamrin profile image
Amrin

Thanks Rai.
I'm learning web accesibility :D
will do for the next projects.

Collapse
 
raibtoffoletto profile image
Raí B. Toffoletto

A hreat writer here on DEV is inhuofficial .
His articles have been helping me to rethink a lot of a11y. Go check him out.

Thread Thread
 
coderamrin profile image
Amrin

Thanks Rai

Thread Thread
 
grahamthedev profile image
GrahamTheDev

Aww I am blushing, thanks for the mention! ❤️

Collapse
 
raibtoffoletto profile image
Raí B. Toffoletto

A hreat writer here on DEV is @inhuofficial .
His articles have been helping me to rethink a lot of a11y. Go check him out.

Collapse
 
codesushil profile image
Code With Sushil

Nice

Collapse
 
coderamrin profile image
Amrin

thanks Sushil

Collapse
 
leticiacareli profile image
leticiacareli

Thanks!

Some comments have been hidden by the post's author - find out more