Introduction

A well-designed navigation bar is the backbone of any website. It guides users, reinforces your brand, and must work flawlessly on every screen size. In this tutorial, you'll build a fully responsive navbar from scratch using only HTML, CSS, and vanilla JavaScript — no frameworks required.

What You'll Build

  • A horizontal desktop nav with logo and links
  • A hamburger menu that opens a mobile drawer
  • Smooth CSS transitions for the menu toggle
  • Accessible markup with aria- attributes

Step 1: HTML Structure

Start with semantic HTML. Use <nav> as the landmark, a logo anchor, an unordered list of links, and a button for the hamburger toggle.

<nav class="navbar" aria-label="Main navigation">
  <a href="/" class="nav-logo">MySite</a>
  <button class="nav-toggle" aria-expanded="false" aria-controls="nav-menu">
    <span class="bar"></span>
    <span class="bar"></span>
    <span class="bar"></span>
  </button>
  <ul class="nav-menu" id="nav-menu">
    <li><a href="/about">About</a></li>
    <li><a href="/blog">Blog</a></li>
    <li><a href="/contact">Contact</a></li>
  </ul>
</nav>

Step 2: CSS Styling

Style the navbar for desktop first, then use a max-width media query to handle mobile layouts.

.navbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1rem 2rem;
  background: #0F4C81;
}
.nav-menu { display: flex; gap: 1.5rem; list-style: none; }
.nav-toggle { display: none; background: none; border: none; cursor: pointer; }
.bar { display: block; width: 25px; height: 3px; background: #fff; margin: 5px 0; transition: 0.3s; }

@media (max-width: 768px) {
  .nav-toggle { display: block; }
  .nav-menu {
    position: fixed; top: 60px; right: -100%;
    flex-direction: column; background: #0F4C81;
    width: 60%; height: 100vh; padding: 2rem;
    transition: right 0.3s ease;
  }
  .nav-menu.open { right: 0; }
}

Step 3: JavaScript Toggle Logic

Add a small script to toggle the .open class and update the aria-expanded attribute for accessibility.

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

toggle.addEventListener('click', () => {
  const isOpen = menu.classList.toggle('open');
  toggle.setAttribute('aria-expanded', isOpen);
});

Step 4: Animated Hamburger Icon

Add CSS rules that transform the three bars into an "X" when the menu is open, giving users clear visual feedback.

.nav-toggle[aria-expanded="true"] .bar:nth-child(1) { transform: translateY(8px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] .bar:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] .bar:nth-child(3) { transform: translateY(-8px) rotate(-45deg); }

Accessibility Checklist

  1. Use <button> (not a <div>) for the toggle so it's keyboard-focusable.
  2. Set aria-expanded dynamically with JavaScript.
  3. Ensure sufficient color contrast between link text and background.
  4. Close the menu when a link is clicked on mobile.

Wrapping Up

You now have a responsive, accessible navbar with zero dependencies. From here you can extend it with dropdown submenus, active-link highlighting, or a sticky scroll effect. The key takeaway: keep the HTML semantic, the CSS mobile-aware, and the JavaScript minimal.