Responsive Navigation Bar (Header) with Mobile Menu & Dropdown Source Code
Create a folder with three files: index.html, style.css, and script.js.
1. HTML (index.html)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Responsive Navbar with Mobile Menu & Dropdown</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<!-- Website Header / Navigation Bar -->
<header id="siteHeader" class="site-header">
<nav class="navbar" aria-label="Main Navigation">
<!-- Brand Logo -->
<a href="#" class="brand-logo">
<span class="logo-mark">NX</span>
<span class="logo-text">NitroX Web</span>
</a>
<!-- Mobile Hamburger Button -->
<button
id="menuToggle"
class="menu-toggle"
type="button"
aria-label="Toggle Menu"
aria-expanded="false"
aria-controls="navMenu"
>
<span class="bar"></span>
<span class="bar"></span>
<span class="bar"></span>
</button>
<!-- Navigation Links & CTA -->
<div id="navMenu" class="nav-menu">
<ul class="nav-list">
<li><a href="#home" class="nav-link active">Home</a></li>
<!-- Dropdown Menu Item -->
<li class="dropdown">
<button
type="button"
class="nav-link dropdown-toggle"
aria-expanded="false"
>
Resources
<svg class="chevron-icon" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="6 9 12 15 18 9"></polyline>
</svg>
</button>
<ul class="dropdown-menu">
<li><a href="#tutorials" class="dropdown-item">HTML & CSS Guides</a></li>
<li><a href="#javascript" class="dropdown-item">JavaScript Snippets</a></li>
<li><a href="#components" class="dropdown-item">UI Components</a></li>
<li><a href="#templates" class="dropdown-item">Free Website Templates</a></li>
</ul>
</li>
<li><a href="#projects" class="nav-link">Projects</a></li>
<li><a href="#articles" class="nav-link">Articles</a></li>
<li><a href="#contact" class="nav-link">Contact</a></li>
</ul>
<!-- Header Call-To-Action Buttons -->
<div class="nav-actions">
<a href="#login" class="btn-secondary">Sign In</a>
<a href="#signup" class="btn-primary">Get Started</a>
</div>
</div>
</nav>
</header>
<!-- Demo Hero Section (To test sticky scroll & mobile menu overlay) -->
<main class="hero-demo">
<div class="hero-container">
<span class="pill-badge">Essential Website Component</span>
<h1>Responsive Sticky Navbar with Dropdown & Mobile Drawer</h1>
<p>Resize your browser window or scroll down to test the sticky glassmorphism header, accessible dropdown menu, and animated mobile hamburger navigation.</p>
</div>
</main>
<script src="script.js"></script>
</body>
</html>
2. CSS (style.css)
/* ==========================================================================
CSS Variables (Easy Brand Customization)
========================================================================== */
:root {
--bg-page: #090d16;
--bg-header: rgba(15, 23, 42, 0.85);
--bg-dropdown: #131c31;
--border-color: #1e293b;
--text-main: #f8fafc;
--text-muted: #94a3b8;
--accent-color: #10b981;
--accent-hover: #059669;
--header-height: 72px;
--radius-md: 10px;
--transition: 0.25s cubic-bezier(0.4, 0, 0.2, 1);
--shadow-lg: 0 15px 30px -10px rgba(0, 0, 0, 0.5);
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background-color: var(--bg-page);
color: var(--text-main);
line-height: 1.6;
min-height: 180vh; /* Extra height to test sticky scrolling */
}
ul {
list-style: none;
}
a {
text-decoration: none;
color: inherit;
}
/* ==========================================================================
Header & Navbar Container
========================================================================== */
.site-header {
position: sticky;
top: 0;
z-index: 1000;
width: 100%;
height: var(--header-height);
background-color: var(--bg-header);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
border-bottom: 1px solid transparent;
transition: border-color var(--transition), box-shadow var(--transition);
}
/* Added via JS when page scrolls down */
.site-header.scrolled {
border-bottom-color: var(--border-color);
box-shadow: var(--shadow-lg);
}
.navbar {
max-width: 1200px;
height: 100%;
margin: 0 auto;
padding: 0 1.5rem;
display: flex;
align-items: center;
justify-content: space-between;
}
/* ==========================================================================
Brand Logo
========================================================================== */
.brand-logo {
display: inline-flex;
align-items: center;
gap: 0.65rem;
font-weight: 800;
font-size: 1.2rem;
letter-spacing: -0.02em;
}
.logo-mark {
background-color: var(--accent-color);
color: #05080e;
font-weight: 900;
font-size: 0.9rem;
width: 34px;
height: 34px;
border-radius: 8px;
display: inline-flex;
align-items: center;
justify-content: center;
}
/* ==========================================================================
Desktop Navigation Links & Dropdown
========================================================================== */
.nav-menu {
display: flex;
align-items: center;
gap: 2rem;
}
.nav-list {
display: flex;
align-items: center;
gap: 0.5rem;
}
.nav-link {
display: inline-flex;
align-items: center;
gap: 0.35rem;
padding: 0.5rem 0.85rem;
font-size: 0.92rem;
font-weight: 600;
color: var(--text-muted);
background: transparent;
border: none;
border-radius: 8px;
cursor: pointer;
font-family: inherit;
transition: color var(--transition), background-color var(--transition);
}
.nav-link:hover,
.nav-link.active {
color: var(--text-main);
background-color: rgba(255, 255, 255, 0.05);
}
.nav-link.active {
color: var(--accent-color);
}
/* Dropdown Menu */
.dropdown {
position: relative;
}
.chevron-icon {
transition: transform var(--transition);
}
.dropdown.open .chevron-icon {
transform: rotate(180deg);
}
.dropdown-menu {
position: absolute;
top: calc(100% + 10px);
left: 0;
min-width: 220px;
background-color: var(--bg-dropdown);
border: 1px solid var(--border-color);
border-radius: var(--radius-md);
padding: 0.5rem;
box-shadow: var(--shadow-lg);
opacity: 0;
visibility: hidden;
transform: translateY(8px);
transition: opacity var(--transition), transform var(--transition), visibility var(--transition);
}
.dropdown.open .dropdown-menu {
opacity: 1;
visibility: visible;
transform: translateY(0);
}
.dropdown-item {
display: block;
padding: 0.6rem 0.85rem;
font-size: 0.88rem;
font-weight: 500;
color: var(--text-muted);
border-radius: 6px;
transition: background-color var(--transition), color var(--transition);
}
.dropdown-item:hover {
background-color: rgba(16, 185, 129, 0.12);
color: var(--accent-color);
}
/* ==========================================================================
Action Buttons
========================================================================== */
.nav-actions {
display: flex;
align-items: center;
gap: 0.75rem;
}
.btn-secondary {
padding: 0.5rem 1rem;
font-size: 0.88rem;
font-weight: 600;
color: var(--text-main);
border: 1px solid var(--border-color);
border-radius: 8px;
transition: border-color var(--transition);
}
.btn-secondary:hover {
border-color: var(--text-muted);
}
.btn-primary {
padding: 0.5rem 1.1rem;
font-size: 0.88rem;
font-weight: 700;
background-color: var(--accent-color);
color: #05080e;
border-radius: 8px;
transition: background-color var(--transition);
}
.btn-primary:hover {
background-color: var(--accent-hover);
}
/* ==========================================================================
Mobile Hamburger Button (Hidden on Desktop)
========================================================================== */
.menu-toggle {
display: none;
flex-direction: column;
justify-content: center;
gap: 5px;
width: 40px;
height: 40px;
background: transparent;
border: 1px solid var(--border-color);
border-radius: 8px;
padding: 8px;
cursor: pointer;
}
.menu-toggle .bar {
width: 100%;
height: 2px;
background-color: var(--text-main);
border-radius: 2px;
transition: transform var(--transition), opacity var(--transition);
}
/* Hamburger to "X" Animation */
.menu-toggle.active .bar:nth-child(1) {
transform: translateY(7px) rotate(45deg);
}
.menu-toggle.active .bar:nth-child(2) {
opacity: 0;
}
.menu-toggle.active .bar:nth-child(3) {
transform: translateY(-7px) rotate(-45deg);
}
/* ==========================================================================
Demo Hero Section
========================================================================== */
.hero-demo {
max-width: 800px;
margin: 5rem auto;
padding: 0 1.5rem;
text-align: center;
}
.pill-badge {
display: inline-block;
background: rgba(16, 185, 129, 0.12);
color: var(--accent-color);
font-size: 0.75rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.05em;
padding: 0.35rem 0.85rem;
border-radius: 999px;
margin-bottom: 1rem;
}
.hero-demo h1 {
font-size: 2.5rem;
font-weight: 800;
letter-spacing: -0.03em;
margin-bottom: 1rem;
}
.hero-demo p {
color: var(--text-muted);
font-size: 1.05rem;
}
/* ==========================================================================
Responsive Mobile Breakpoint (<= 820px)
========================================================================== */
@media (max-width: 820px) {
.menu-toggle {
display: flex;
}
.nav-menu {
position: fixed;
top: var(--header-height);
left: 0;
width: 100%;
background-color: #0d1424;
border-bottom: 1px solid var(--border-color);
flex-direction: column;
align-items: stretch;
gap: 1.25rem;
padding: 1.5rem;
box-shadow: var(--shadow-lg);
opacity: 0;
visibility: hidden;
transform: translateY(-10px);
transition: opacity var(--transition), transform var(--transition), visibility var(--transition);
}
.nav-menu.active {
opacity: 1;
visibility: visible;
transform: translateY(0);
}
.nav-list {
flex-direction: column;
align-items: stretch;
gap: 0.25rem;
}
.nav-link {
width: 100%;
justify-content: space-between;
padding: 0.75rem 1rem;
}
.dropdown-menu {
position: static;
box-shadow: none;
border: none;
border-left: 2px solid var(--border-color);
margin-left: 1rem;
padding: 0.25rem 0 0.25rem 0.75rem;
background: transparent;
display: none;
opacity: 1;
visibility: visible;
transform: none;
}
.dropdown.open .dropdown-menu {
display: block;
}
.nav-actions {
flex-direction: column;
padding-top: 0.75rem;
border-top: 1px solid var(--border-color);
}
.btn-secondary,
.btn-primary {
width: 100%;
text-align: center;
padding: 0.75rem;
}
.hero-demo h1 {
font-size: 1.85rem;
}
}
3. JavaScript (script.js)
document.addEventListener('DOMContentLoaded', () => {
const siteHeader = document.getElementById('siteHeader');
const menuToggle = document.getElementById('menuToggle');
const navMenu = document.getElementById('navMenu');
const dropdowns = document.querySelectorAll('.dropdown');
const navLinks = document.querySelectorAll('.nav-list a');
// 1. Toggle Mobile Hamburger Menu
const toggleMobileMenu = () => {
const isExpanded = menuToggle.getAttribute('aria-expanded') === 'true';
menuToggle.setAttribute('aria-expanded', !isExpanded);
menuToggle.classList.toggle('active');
navMenu.classList.toggle('active');
};
menuToggle.addEventListener('click', toggleMobileMenu);
// 2. Handle Dropdown Menu Toggling
dropdowns.forEach((dropdown) => {
const toggleBtn = dropdown.querySelector('.dropdown-toggle');
toggleBtn.addEventListener('click', (e) => {
e.stopPropagation();
const isOpen = dropdown.classList.contains('open');
// Close any other open dropdowns first
dropdowns.forEach((d) => {
d.classList.remove('open');
d.querySelector('.dropdown-toggle').setAttribute('aria-expanded', 'false');
});
// Toggle current dropdown
if (!isOpen) {
dropdown.classList.add('open');
toggleBtn.setAttribute('aria-expanded', 'true');
}
});
});
// 3. Close Dropdowns & Mobile Menu When Clicking Outside
document.addEventListener('click', (e) => {
// Close dropdowns if click is outside
dropdowns.forEach((dropdown) => {
if (!dropdown.contains(e.target)) {
dropdown.classList.remove('open');
dropdown.querySelector('.dropdown-toggle').setAttribute('aria-expanded', 'false');
}
});
// Close mobile drawer if click is outside the header
if (!siteHeader.contains(e.target) && navMenu.classList.contains('active')) {
menuToggle.setAttribute('aria-expanded', 'false');
menuToggle.classList.remove('active');
navMenu.classList.remove('active');
}
});
// 4. Close Menus on Escape Key Press (Accessibility)
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
dropdowns.forEach((d) => {
d.classList.remove('open');
d.querySelector('.dropdown-toggle').setAttribute('aria-expanded', 'false');
});
if (navMenu.classList.contains('active')) {
toggleMobileMenu();
menuToggle.focus();
}
}
});
// 5. Close Mobile Menu When Clicking Any Navigation Link
navLinks.forEach((link) => {
link.addEventListener('click', () => {
if (navMenu.classList.contains('active')) {
toggleMobileMenu();
}
});
});
// 6. Sticky Header Scroll Shadow Effect
window.addEventListener('scroll', () => {
if (window.scrollY > 15) {
siteHeader.classList.add('scrolled');
} else {
siteHeader.classList.remove('scrolled');
}
});
});
How to Build a Responsive Sticky Navigation Bar with Dropdown & Mobile Menu in HTML, CSS & JS
The navigation bar is the single most important UI component on any website. It sits at the top of every page, guides visitors to your core content, and shapes their first impression of your brand. Yet many websites still rely on heavy CSS frameworks just to make a mobile hamburger button open and close.
In this guide, we will walk through how to build a lightweight, accessible, and responsive navigation bar from scratch using semantic HTML5, modern CSS Flexbox, and vanilla JavaScript—complete with a clickable dropdown submenu, a smooth hamburger-to-X animation, and a frosted-glass sticky scroll effect.
1. Structuring Semantic HTML for SEO and Accessibility
Search engines and screen readers rely on semantic landmarks to understand your site’s hierarchy. Instead of wrapping links in generic <div> tags, our template uses:
<header class="site-header">: Defines the top banner landmark of the page.<nav class="navbar" aria-label="Main Navigation">: Explicitly tells assistive technologies that this block contains the primary site links.<button aria-expanded="false">: Used for both the mobile hamburger icon and the dropdown trigger so keyboard users can open and close menus usingEnterorSpace, and exit cleanly with theEscapekey.
2. How the Pure CSS Hamburger-to-X Animation Works
Instead of loading external icon fonts or swapping SVG files when the mobile menu opens, we construct the hamburger icon using three simple <span class="bar"> elements stacked inside a flex container with a 5px gap.
When each bar has a 2px height and a 5px gap between them, the distance from the center of the top bar to the center of the middle bar is exactly 7px (2\text{px} + 5\text{px}). When JavaScript toggles the .active class on the button, CSS translates the top and bottom bars inward by 7px and rotates them in opposite 45^\circ angles while fading out the middle bar:
.menu-toggle.active .bar:nth-child(1) {
transform: translateY(7px) rotate(45deg);
}
.menu-toggle.active .bar:nth-child(2) {
opacity: 0;
}
.menu-toggle.active .bar:nth-child(3) {
transform: translateY(-7px) rotate(-45deg);
}
3. Switching from Desktop Flexbox to a Mobile Drawer
On desktop screens (> 820px), .navbar and .nav-menu sit side-by-side in a horizontal row using display: flex, and the dropdown submenu floats below its parent link using position: absolute.
When the viewport shrinks below 820px, our @media (max-width: 820px) query transforms the layout automatically:
- The
.menu-togglebutton changes fromdisplay: nonetodisplay: flex. - The
.nav-menuswitches toposition: fixedright below the header (top: var(--header-height)), stacking links vertically. - The
.dropdown-menuswitches toposition: staticwith a subtle left border, acting like a clean mobile accordion inside the drawer rather than overlapping other links.
4. Customizing This Navbar for Your Website
- Changing the Mobile Breakpoint: If your navigation bar has more than 6 links, you may want the mobile hamburger menu to appear on tablets too. Simply change
@media (max-width: 820px)instyle.cssto@media (max-width: 992px). - Switching to Light Mode: Change the
:rootvariables at the top ofstyle.css: set--bg-headertorgba(255, 255, 255, 0.85),--text-mainto#0f172a, and--border-colorto#e2e8f0. - Adding More Dropdowns: Duplicate the
<li class="dropdown">...</li>block insideindex.html. Because our JavaScript usesdocument.querySelectorAll('.dropdown'), you can add as many dropdown menus as you need without touching a single line of JS.
