HTML Structure
Start with semantic HTML. The <nav> element with aria-label makes the navbar accessible to screen readers. The hamburger button needs aria-expanded toggled by JavaScript.
HTML – Navigation structure
<header class="navbar" id="navbar">
<a href="/" class="navbar__logo" aria-label="Home">
<img src="/logo.png" alt="ylearner" width="120" height="36">
</a>
<!-- Desktop nav links -->
<nav class="navbar__nav" aria-label="Main navigation">
<ul class="navbar__list" role="list">
<li><a href="/" class="navbar__link navbar__link--active">Home</a></li>
<li class="navbar__item--dropdown">
<button class="navbar__link navbar__dropdown-toggle" aria-expanded="false">
Courses ▾
</button>
<ul class="navbar__dropdown" role="list">
<li><a href="/python/" class="navbar__dropdown-item">🐍 Python</a></li>
<li><a href="/csslessons/" class="navbar__dropdown-item">🎨 CSS</a></li>
<li><a href="/html/" class="navbar__dropdown-item">🌐 HTML</a></li>
</ul>
</li>
<li><a href="/about.html" class="navbar__link">About</a></li>
</ul>
</nav>
<a href="/python/what-is-python.html" class="navbar__cta">Start Learning →</a>
<!-- Hamburger toggle -->
<button class="navbar__hamburger" id="hamburger"
aria-label="Toggle menu" aria-expanded="false"
aria-controls="mobileMenu">
<span></span><span></span><span></span>
</button>
</header>
Base Navbar CSS
CSS – Navbar base
:root {
--nav-height: 64px;
--nav-bg: #ffffff;
--nav-text: #1a1a1a;
--nav-primary: #1572B6;
--nav-border: #e0e0e0;
}
.navbar {
display: flex;
align-items: center;
gap: 2rem;
height: var(--nav-height);
padding: 0 2rem;
background: var(--nav-bg);
border-bottom: 1px solid var(--nav-border);
position: sticky;
top: 0;
z-index: 100;
box-shadow: 0 1px 8px rgba(0,0,0,.06);
}
.navbar__logo img { display: block; }
.navbar__nav { margin-right: auto; } /* push cta to right */
.navbar__list {
display: flex;
list-style: none;
margin: 0;
padding: 0;
gap: .25rem;
}
.navbar__link {
display: flex;
align-items: center;
gap: .3rem;
padding: .5rem .75rem;
color: var(--nav-text);
text-decoration: none;
font-weight: 500;
font-size: .95rem;
border-radius: 6px;
background: none;
border: none;
cursor: pointer;
transition: background .15s, color .15s;
}
.navbar__link:hover { background: #f0f0f0; color: var(--nav-primary); }
.navbar__link--active { color: var(--nav-primary); font-weight: 700; }
.navbar__cta {
padding: .5rem 1.2rem;
background: var(--nav-primary);
color: #fff;
border-radius: 6px;
text-decoration: none;
font-weight: 600;
font-size: .9rem;
white-space: nowrap;
transition: background .2s, transform .2s;
}
.navbar__cta:hover { background: #0f5fa0; transform: translateY(-1px); }
.navbar__hamburger { display: none; }
Ad – 336×280
Dropdown Menu
CSS – Dropdown
.navbar__item--dropdown { position: relative; }
.navbar__dropdown {
position: absolute;
top: calc(100% + 8px);
left: 0;
min-width: 180px;
background: #fff;
border: 1px solid var(--nav-border);
border-radius: 8px;
box-shadow: 0 8px 24px rgba(0,0,0,.12);
list-style: none;
margin: 0;
padding: .4rem 0;
/* Hidden by default */
opacity: 0;
visibility: hidden;
transform: translateY(-6px);
transition: opacity .15s, visibility .15s, transform .15s;
z-index: 200;
}
/* Show on hover of parent li, or when toggle has aria-expanded=true */
.navbar__item--dropdown:hover .navbar__dropdown,
.navbar__item--dropdown:focus-within .navbar__dropdown {
opacity: 1;
visibility: visible;
transform: translateY(0);
}
.navbar__dropdown-item {
display: flex;
align-items: center;
gap: .5rem;
padding: .5rem 1rem;
color: var(--nav-text);
text-decoration: none;
font-size: .9rem;
transition: background .12s;
}
.navbar__dropdown-item:hover { background: #f5f5f5; color: var(--nav-primary); }
Hamburger Menu (Mobile)
CSS – Hamburger
.navbar__hamburger {
display: none;
flex-direction: column;
gap: 5px;
background: none;
border: none;
cursor: pointer;
padding: .5rem;
margin-left: auto;
}
.navbar__hamburger span {
display: block;
width: 24px;
height: 2px;
background: var(--nav-text);
border-radius: 2px;
transition: all .25s ease;
}
/* Animate to X when open */
.navbar__hamburger[aria-expanded="true"] span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.navbar__hamburger[aria-expanded="true"] span:nth-child(2) { opacity: 0; transform: scaleX(0); }
.navbar__hamburger[aria-expanded="true"] span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
@media (max-width: 768px) {
.navbar__hamburger { display: flex; }
.navbar__nav, .navbar__cta { display: none; }
/* Mobile menu — full-width dropdown below header */
.navbar__nav.mobile-open {
display: block;
position: fixed;
top: var(--nav-height);
left: 0;
right: 0;
background: #fff;
border-bottom: 1px solid var(--nav-border);
box-shadow: 0 8px 24px rgba(0,0,0,.12);
padding: 1rem;
animation: slideDown .2s ease;
z-index: 99;
}
.navbar__nav.mobile-open .navbar__list { flex-direction: column; gap: .25rem; }
.navbar__nav.mobile-open .navbar__link { width: 100%; font-size: 1rem; padding: .65rem .75rem; }
.navbar__nav.mobile-open .navbar__dropdown { position: static; opacity: 1; visibility: visible; transform: none; box-shadow: none; border: none; padding-left: 1rem; }
}
@keyframes slideDown {
from { opacity: 0; transform: translateY(-8px); }
to { opacity: 1; transform: translateY(0); }
}
JavaScript Toggle
JS – Hamburger toggle
const hamburger = document.getElementById('hamburger');
const nav = document.querySelector('.navbar__nav');
hamburger.addEventListener('click', () => {
const open = hamburger.getAttribute('aria-expanded') === 'true';
hamburger.setAttribute('aria-expanded', String(!open));
nav.classList.toggle('mobile-open', !open);
});
// Close on outside click
document.addEventListener('click', (e) => {
if (!e.target.closest('.navbar')) {
hamburger.setAttribute('aria-expanded', 'false');
nav.classList.remove('mobile-open');
}
});
// Close on Escape key
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
hamburger.setAttribute('aria-expanded', 'false');
nav.classList.remove('mobile-open');
hamburger.focus(); // return focus to toggle button
}
});
📋 Key Patterns
- Sticky header:
position: sticky; top: 0;withz-indexhigh enough to stay above content. - Dropdown:
opacity + visibility + transforminstead ofdisplay:none— allows CSS transitions. - Hamburger X animation: rotate and translate the three spans using
aria-expandedas the state toggle. - Accessibility: use
aria-expanded,aria-label,aria-controls; close on Escape; return focus to toggle.