I created a custom navigation, which turns into a hamburger icon on smaller devices. When clicked, the icon expands a full-width menu, however the problem is that the user can still scroll down as if they're viewing my content, so there's essentially the option to pointlessly scroll, which I would like to disable. I also have a submenu under one of my links, and when you click the parent
document.addEventListener('DOMContentLoaded', function() {
// Using const for non-reassignable variables
const hamburger = document.getElementById('hamburger-custom');
const navMenu = document.getElementById('custom-nav-menu');
const closeButton = document.getElementById('mobile-close-icon');
if (!hamburger || !navMenu || !closeButton) {
console.error('Critical elements for the navigation menu are missing!');
return; // Stop the execution if the elements are not found
}
// Improved toggle function
function toggleMenu() {
navMenu.classList.toggle('active'); // This single line replaces the whole if/else block
// Managing ARIA-expanded attribute for better accessibility
const isExpanded = navMenu.classList.contains('active');
hamburger.setAttribute('aria-expanded', isExpanded);
closeButton.setAttribute('aria-expanded', isExpanded);
// Handling the close icon display state without relying on pointerEvents
const closeIconWrapper = document.getElementById('mobile-close-icon-wrapper');
if (closeIconWrapper) {
closeIconWrapper.style.display = isExpanded ? 'block' : 'none';
}
}
// Event listeners
hamburger.addEventListener('click', toggleMenu);
closeButton.addEventListener('click', toggleMenu);
// Optionally: Listen for the 'Esc' key to close the menu
window.addEventListener('keydown', function(event) {
if (event.key === 'Escape' && navMenu.classList.contains('active')) {
toggleMenu();
}
});
});
.vassil-main-navigation .custom-nav-menu {
list-style-type: none;
margin: 0;
padding: 0;
display: flex;
justify-content: space-between;
}
.vassil-main-navigation .custom-nav-menu li {
position: relative;
}
.vassil-main-navigation .custom-nav-menu a {
text-decoration: none;
color: inherit;
display: flex;
align-items: center;
height: 100%;
}
.vassil-main-navigation .custom-nav-menu a span {
display: inline-block;
position: relative;
}
.vassil-main-navigation .custom-nav-menu a span::after {
content: '';
position: absolute;
width: 0;
height: 1px;
bottom: 0;
left: 0;
background-color: black;
transition: width 0.4s;
visibility: hidden;
}
.vassil-main-navigation .custom-nav-menu a:hover span::after {
visibility: visible;
width: 100%;
}
.vassil-main-navigation .custom-nav-menu .submenu {
display: none;
position: absolute;
top: 100%;
left: 0;
padding: 0;
list-style: none;
background-color: #fff;
z-index: 1;
}
.vassil-main-navigation .custom-nav-menu .has-submenu:hover .submenu {
display: block;
}
.vassil-main-navigation .custom-nav-menu .submenu li a {
padding: 10px 25px;
white-space: nowrap;
}
.has-submenu > a:after {
content: "▼";
font-size: 10px;
margin-left: 5px;
}
#hamburger-custom {
display: none;
}
/* Media query for smaller screens (max-width: 1024px) */
@media (max-width: 1024px) {
#hamburger-custom {
display: flex;
flex-direction: column;
justify-content: space-around;
width: 30px;
height: 25px;
background: transparent;
border: none;
cursor: pointer;
padding: 0;
z-index: 10;
}
#hamburger-custom:focus {
outline: none;
}
#hamburger-custom .bar {
display: block;
width: 30px;
height: 3px;
background: #333;
border-radius: 10px;
transition: 0.3s ease-in-out;
}
.vassil-main-navigation .custom-nav-menu {
position: fixed; /* Fixed positioning to cover the entire viewport */
top: 0;
left: -100%; /* Start off screen left */
width: 100%;
height: 100vh; /* Full height of the viewport */
flex-direction: column;
justify-content: center; /* Center the content vertically */
list-style: none;
background-color: rgba(255, 255, 255, 0.95);
z-index: 1000; /* High z-index to stay on top of other elements */
transition: left 0.3s ease;
}
.vassil-main-navigation .custom-nav-menu.active {
left: 0;
}
.vassil-main-navigation .custom-nav-menu li a {
text-align: center; /* Center the link text */
padding: 15px; /* Add some padding */
display: block; /* Make links take up the whole line */
}
.vassil-main-navigation .custom-nav-menu .has-submenu .submenu {
display:none;
position: absolute; /* Already there, keeps the submenu out of the document flow */
top: 100%; /* Changed from '50px' to make it appear right below the parent menu item */
left: 0; /* Changed from '60%' to align with the left edge of the parent menu item */
width: 100%; /* Add this to ensure submenu takes full width of parent */
box-shadow: none; /* Optional: in case you don't want box shadow effect */
z-index: 1000; /* Optional: to ensure the submenu appears above other elements */
background-color: #fff; /* Already there, for a white background */
}
#mobile-close-icon-wrapper {
position: fixed;
top: 0;
right: 0;
z-index: 1002;
display: none;
padding: 10px;
}
.custom-nav-menu.active + #mobile-close-icon-wrapper {
display: block;
}
.mobile-close-icon {
font-size: 30px;
color: #333;
text-decoration: none;
}
}
@media (min-width: 1025px) {
#mobile-close-icon-wrapper {
display: none !important;}
}
<nav class="vassil-main-navigation">
<!-- Hamburger button -->
<button class="hamburger-custom" id="hamburger-custom">
<span class="bar"></span>
<span class="bar"></span>
<span class="bar"></span>
</button>
<!-- Navigation Menu -->
<ul class="custom-nav-menu" id="custom-nav-menu">
<li><a href="https://houniqueconstruction.com/"><span>Home</span></a></li>
<li><a href="https://houniqueconstruction.com/about-us/"><span>About Us</span> </a></li>
<li class="has-submenu">
<a href="#"><span>Services</span></a>
<ul class="submenu">
<li><a href="https://houniqueconstruction.com/kitchen-remodeling/"><span>Kitchen Remodeling</span></a></li>
<li><a href="https://houniqueconstruction.com/bathroom-remodeling/"><span>Bathroom Remodeling</span></a></li>
<li><a href="https://houniqueconstruction.com/complete-remodeling/"><span>Complete Remodeling</span></a></li>
</ul>
</li>
<li><a href="https://houniqueconstruction.com/gallery/"><span>Gallery</span></a></li>
<li><a href="https://houniqueconstruction.com/contact/"><span>Contact Us</span></a></li>
</ul>
<!-- 'X' button to close the fullscreen menu -->
<div id="mobile-close-icon-wrapper">
<a href="javascript:void(0)" class="mobile-close-icon" id="mobile-close-icon">×</a>
</div>
</nav>
Improved toggle function for Disable scrolling on full width mobile menu
function toggleMenu() {
// Add or remove overflow: hidden to the body
const body = document.body;
if (isExpanded) {
body.style.overflow = 'hidden';
} else {
body.style.overflow = 'auto';
}
}
add allow submenu to close after clicking parent <li>
a second time
// remove for if you set with event
.vassil-main-navigation .custom-nav-menu .has-submenu:hover .submenu {
display: block;
}
// add for active class for toggle event
.vassil-main-navigation .custom-nav-menu .has-submenu.active .submenu {
display: block;
}
add js
// Get the "Services" link and its submenu
const servicesLink = document.querySelector('.has-submenu');
const submenu = servicesLink.querySelector('.submenu');
// Add event listeners to handle click and mouse enter/leave
servicesLink.addEventListener('click', function(event) {
event.preventDefault(); // Prevent the link from navigating
// Toggle the 'active' class to control submenu display
servicesLink.classList.toggle('active');
if (servicesLink.classList.contains('active')) {
submenu.style.display = 'block';
} else {
submenu.style.display = 'none';
}
});
servicesLink.addEventListener('mouseenter', function() {
if (!servicesLink.classList.contains('active')) {
servicesLink.classList.add('active');
submenu.style.display = 'block';
}
});
servicesLink.addEventListener('mouseleave', function() {
if (servicesLink.classList.contains('active')) {
servicesLink.classList.remove('active');
submenu.style.display = 'none';
}
});