OnlineCBT Logo OnlineCBT
CSS Tutorial
CSS · LESSON 49

CSS Project: Modern Responsive Navigation Bar

By Ratan Updated: 15 Oct 2026

Build a complete responsive flexbox navbar with hamburger mobile menu toggle.

Level: Beginner to Advanced
Duration: ~60 Mins Deep-Dive

Build a responsive navigation that remains usable

This project combines flex layout, a narrow-screen drawer, visible focus and a small amount of JavaScript for disclosure state. The links remain visible if JavaScript is unavailable. Use real links and a real button; CSS alone should not impersonate an interactive menu control.

HTML


  

Learning dashboard

CSS

*, *::before, *::after { box-sizing: border-box; }
.tech-lesson-content { margin: 0; font: 1rem/1.5 system-ui, sans-serif; }
.site-header { background: #172554; color: white; }
.site-nav {
  position: relative; display: flex; align-items: center;
  flex-wrap: wrap; gap: 1rem; max-width: 70rem;
  margin-inline: auto; padding: 1rem;
}
.brand { font-weight: 700; margin-right: auto; }
.site-nav a { color: white; text-underline-offset: 0.25em; }
.nav-links { display: flex; gap: 1rem; list-style: none; margin: 0; padding: 0; }
.menu-toggle { display: none; padding: 0.6rem 1rem; font: inherit; }
a:focus-visible, button:focus-visible {
  outline: 3px solid #fbbf24; outline-offset: 4px;
}
main { max-width: 70rem; margin-inline: auto; padding: 1rem; }
@media (max-width: 44rem) {
  .nav-links { flex-basis: 100%; flex-direction: column; }
  .js .menu-toggle { display: inline-block; }
  .js .nav-links {
    display: none; position: absolute; right: 0; top: 100%;
    width: min(20rem, 100vw); padding: 1.25rem;
    background: #172554; box-shadow: 0 8px 18px rgb(0 0 0 / 0.2);
    z-index: 20;
  }
  .js .nav-links.is-open { display: flex; }
  .nav-links a { display: block; padding: 0.5rem; }
}

JavaScript, placed after the navigation

const toggle = document.querySelector('.menu-toggle');
const links = document.querySelector('#primary-links');
if (toggle && links) {
  document.documentElement.classList.add('js');
  toggle.hidden = false;
  function closeMenu() {
    links.classList.remove('is-open');
    toggle.setAttribute('aria-expanded', 'false');
  }
  toggle.addEventListener('click', () => {
    const opened = links.classList.toggle('is-open');
    toggle.setAttribute('aria-expanded', String(opened));
  });
  document.addEventListener('keydown', event => {
    if (event.key === 'Escape' && links.classList.contains('is-open')) {
      closeMenu();
      toggle.focus();
    }
  });
  links.addEventListener('click', event => {
    if (event.target.closest('a')) closeMenu();
  });
}

Expected behavior

On a wide viewport, the links appear in a row and the menu button is hidden. At a narrow width, the button opens a right-aligned dropdown drawer. This is a non-modal disclosure, so it does not lock page scrolling or trap focus. Escape closes an open drawer and restores focus to its button.

Verification checklist

  1. Tab to Menu, activate it with Enter or Space, and reach each link with Tab.
  2. Press Escape while open; verify the state and focus.
  3. Disable JavaScript: links should remain visible and usable in normal flow.
  4. Test 320px width, long labels and 200% zoom.
  5. Replace the example href values with real destinations and confirm there are no dead links.

Extensions

Add an active-page aria-current="page" marker. If the design later becomes a modal full-screen drawer, implement its different focus-management and dismissal requirements explicitly rather than merely adding a dark backdrop.

📝 Live Lesson Practice

HTML/CSS JavaScript Python C++ C PHP
⌨️ Practice Inputs (लाइव इनपुट भरें) (खाली होने पर RED, भरने पर GREEN underline)
💻 Code Editor (Monaco VS Code Engine)
👀 Live Preview
Address Contact

+91 7877547686

E-mail

onlinecbtportal@gmail.com

Helpline Number

+91 7877547686


Click To Download
Get it on Google Play

ऐप डाउनलोड करने
के लिए Google Play पर
उपलब्ध है

WhatsApp Chat