Toggle navigation
☰
Home
HTML
CSS
Scripting
Database
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>The Accessible Mega Menu (Definitive Final Version)</title> <style> :root { --color-background: #ffffff; --color-surface: #f8f9fa; --color-text-primary: #212529; --color-text-secondary: #495057; --color-primary: #0d6efd; --color-border: #e9ecef; --font-family-sans-serif: "Segoe UI", -apple-system, sans-serif; --navbar-height: 80px; --container-width: 1200px; --border-radius: 8px; --transition-speed: 0.3s; } *, *::before, *::after { box-sizing: border-box; } body { margin: 0; font-family: var(--font-family-sans-serif); background-color: #f9fafb; line-height: 1.6; } .content { min-height: 150vh; max-width: var(--container-width); margin: 0 auto; padding: calc(var(--navbar-height) + 2rem) 1.5rem; } ul { list-style: none; margin: 0; padding: 0; } a, .mega-menu-toggle { text-decoration: none; color: var(--color-text-secondary); background: none; border: none; font-family: inherit; cursor: pointer; } a:hover, .mega-menu-toggle:hover { color: var(--color-primary); } .navbar { position: sticky; top: 0; z-index: 1001; height: var(--navbar-height); display: flex; align-items: center; background-color: var(--color-background); border-bottom: 1px solid var(--color-border); } .navbar__container { display: flex; align-items: center; justify-content: space-between; width: 100%; max-width: var(--container-width); margin: 0 auto; padding: 0 1.5rem; } .navbar__brand { font-size: 1.5rem; font-weight: 600; color: var(--color-text-primary); } .nav-item { position: relative; } .nav-link, .mega-menu-toggle { display: flex; align-items: center; gap: .5rem; padding: 1rem 1.5rem; font-weight: 500; font-size: 1rem; color: var(--color-text-primary); } .mega-menu { display: none; } .nav-item.is-open > .mega-menu { display: block; } /* ======================================== MOBILE-FIRST STYLES (DEFAULT) ======================================== */ /* The main navigation container (mobile menu panel) */ .navbar__nav { display: none; /* Hidden by default */ position: fixed; top: var(--navbar-height); left: 0; width: 100%; background-color: var(--color-background); height: calc(100vh - var(--navbar-height)); overflow-y: auto; } .navbar__nav.is-open { display: block; } /* Show when toggled */ .nav-list > .nav-item { border-bottom: 1px solid var(--color-border); } .nav-link, .mega-menu-toggle { justify-content: space-between; width: 100%; } /* Sub-menu panel (accordion style) */ .mega-menu { max-height: 0; overflow: hidden; background-color: var(--color-surface); transition: max-height var(--transition-speed) ease; } .nav-item.is-open > .mega-menu { max-height: 1000px; /* Animate to open */ } .mega-menu__content { padding: 1rem 1.5rem; } /* Sub-menu grid (stacks vertically) */ .mega-menu__grid { display: block; } .mega-menu__column:not(:first-child) { margin-top: 1.5rem; } .mega-menu__heading { font-size: .9rem; font-weight: 600; text-transform: uppercase; margin: 0 0 1rem; } .mega-menu__link-list li { margin-bottom: 0.75rem; } /* The hamburger button */ .navbar__mobile-toggle { display: block; border: 1px solid var(--color-border); background: transparent; padding: 0.5rem; cursor: pointer; } /* ======================================== DESKTOP OVERRIDES ======================================== */ @media (min-width: 992px) { .navbar__mobile-toggle { display: none; } /* Hide hamburger */ /* Restore nav to a horizontal layout */ .navbar__nav { display: flex; position: static; height: auto; width: auto; background-color: transparent; overflow: visible; } .nav-list { display: flex; align-items: center; gap: .5rem; } .nav-list > .nav-item { border-bottom: none; } .nav-link, .mega-menu-toggle { padding: .75rem 1rem; border-radius: var(--border-radius); transition: background-color 0.2s, color 0.2s; } .nav-link:hover, .mega-menu-toggle:hover { background-color: var(--color-surface); } /* Restore desktop mega menu styles */ .mega-menu { position: absolute; top: calc(100% + 5px); left: 0; width: 500px; background: var(--color-background); border: 1px solid var(--color-border); border-radius: var(--border-radius); box-shadow: 0 10px 20px rgba(0,0,0,0.1); max-height: none; /* Remove accordion behavior */ } .mega-menu__grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1.5rem; } .mega-menu__column:not(:first-child) { margin-top: 0; } } </style> </head> <body> <header class="navbar"> <div class="navbar__container"> <a href="#" class="navbar__brand">AccessibleCorp</a> <button class="navbar__mobile-toggle" id="mobile-toggle" aria-label="Toggle Navigation" aria-expanded="false" aria-controls="main-nav">☰</button> <nav class="navbar__nav" id="main-nav"> <ul class="nav-list"> <li class="nav-item"><a href="#" class="nav-link">Home</a></li> <li class="nav-item" data-menu> <button class="mega-menu-toggle" aria-haspopup="true" aria-expanded="false" aria-controls="products-menu">Products ▾</button> <div class="mega-menu" id="products-menu"> <div class="mega-menu__content"> <div class="mega-menu__grid"> <div class="mega-menu__column"> <h3 class="mega-menu__heading">For Business</h3> <ul class="mega-menu__link-list"> <li><a href="#">Team Collaboration</a></li><li><a href="#">Cloud Platform</a></li><li><a href="#">Analytics Suite</a></li> </ul> </div> <div class="mega-menu__column"> <h3 class="mega-menu__heading">For Developers</h3> <ul class="mega-menu__link-list"> <li><a href="#">API Documentation</a></li><li><a href="#">SDKs & Libraries</a></li><li><a href="#">Developer Forum</a></li> </ul> </div> </div> </div> </div> </li> <li class="nav-item"><a href="#" class="nav-link">Pricing</a></li> <li class="nav-item" data-menu> <button class="mega-menu-toggle" aria-haspopup="true" aria-expanded="false" aria-controls="contact-menu">Contact ▾</button> <div class="mega-menu" id="contact-menu"> <div class="mega-menu__content"><h3 class="mega-menu__heading">Get In Touch</h3><p>Our team is here to help.</p></div> </div> </li> </ul> </nav> </div> </header> <main class="content"><h1>Accessible Mega Menu</h1></main> <script> document.addEventListener('DOMContentLoaded', () => { const mobileToggle = document.getElementById('mobile-toggle'); const mainNav = document.getElementById('main-nav'); // --- 1. Mobile Hamburger Toggle --- mobileToggle.addEventListener('click', () => { const isOpen = mainNav.classList.toggle('is-open'); mobileToggle.setAttribute('aria-expanded', isOpen); }); // --- 2. Mega Menu Logic (for both views) --- const allMenuContainers = document.querySelectorAll('[data-menu]'); allMenuContainers.forEach(container => { const toggleButton = container.querySelector('.mega-menu-toggle'); const menuPanel = container.querySelector('.mega-menu'); if (!toggleButton || !menuPanel) return; // This repositions the menu ONLY if it will overflow the screen on desktop function positionMenu() { if (window.innerWidth < 992) return; // Only run on desktop menuPanel.style.left = '0'; // Reset first const menuRect = menuPanel.getBoundingClientRect(); const viewportWidth = window.innerWidth; const overflowAmount = menuRect.right - viewportWidth; if (overflowAmount > 0) { menuPanel.style.left = `-${overflowAmount + 20}px`; } } toggleButton.addEventListener('click', (event) => { const parentItem = container; const isExpanded = parentItem.classList.toggle('is-open'); toggleButton.setAttribute('aria-expanded', isExpanded); // Close all other menus allMenuContainers.forEach(otherContainer => { if (otherContainer !== container) { otherContainer.classList.remove('is-open'); otherContainer.querySelector('.mega-menu-toggle').setAttribute('aria-expanded', 'false'); } }); // KEYBOARD NAVIGATION container.addEventListener('keydown', (e) => { // Check if we are on a desktop screen const isDesktopView = window.innerWidth > 992; const menuItems = Array.from(menuPanel.querySelectorAll('a')); if (isDesktopView) { // --- DESKTOP KEYBOARD LOGIC --- const isExpanded = container.getAttribute('aria-expanded') === 'true'; // If user presses ArrowDown on the button, open the menu and focus the first item if (e.target === toggleButton && e.key === 'ArrowDown') { e.preventDefault(); container.setAttribute('aria-expanded', 'true'); if (menuItems.length > 0) menuItems[0].focus(); } // If user presses ArrowUp or ArrowDown inside an open menu if (isExpanded && (e.key === 'ArrowUp' || e.key === 'ArrowDown')) { e.preventDefault(); const activeIndex = menuItems.indexOf(document.activeElement); let newIndex = e.key === 'ArrowDown' ? activeIndex + 1 : activeIndex - 1; if (newIndex >= menuItems.length) newIndex = 0; // Loop to top if (newIndex < 0) newIndex = menuItems.length - 1; // Loop to bottom menuItems[newIndex].focus(); } } // --- UNIVERSAL KEYBOARD LOGIC (Applies to both Mobile & Desktop) --- // If user presses Enter or Space on the main toggle button if (e.target === toggleButton && (e.key === 'Enter' || e.key === 'Space')) { e.preventDefault(); toggleButton.click(); // Simulate a click to trigger the accordion/flyout } // If user presses Escape, close the menu and return focus to the button if (e.key === 'Escape') { container.setAttribute('aria-expanded', 'false'); toggleButton.focus(); } }); if (isExpanded) positionMenu(); // Position only when opening event.preventDefault(); // Stop links from navigating, as they are just toggles }); }); // --- 3. Universal Close Logic --- document.addEventListener('click', (e) => { if (!e.target.closest('.navbar')) { document.querySelectorAll('.nav-item.is-open').forEach(item => { item.classList.remove('is-open'); item.querySelector('[aria-expanded]').setAttribute('aria-expanded', 'false'); }); } }); document.addEventListener('keydown', (e) => { if (e.key === 'Escape') { document.querySelectorAll('.nav-item.is-open').forEach(item => { item.classList.remove('is-open'); item.querySelector('[aria-expanded]').setAttribute('aria-expanded', 'false'); }); } }); }); </script> </body> </html>