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
- Use
<button>(not a<div>) for the toggle so it's keyboard-focusable. - Set
aria-expandeddynamically with JavaScript. - Ensure sufficient color contrast between link text and background.
- 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.