Maintain visibility of the scroll bar but deactivate it when the navigation menu is open

My navigation menu is functioning properly, but the page remains scrollable when it appears over the content. The button's position causes too much jumping if the scrollbar is hidden. I want to disable scrolling on the body when the active class is present. I attempted using CSS properties

position: fixed; overflow-y:scroll
on the body, but this results in double scrolling and does not always revert.

I am hoping that JavaScript can be adjusted to keep the scrollbar visible but non-scrollable while the navigation menu is open. I am uncertain about how to approach this effectively.

const navButtons = document.querySelectorAll('button.nav-action');
const siteNav = document.querySelector('.site-nav');

function onClick(event) {
  siteNav.classList.toggle('active');
}

navButtons.forEach(button => button.addEventListener('click', onClick));
.site-header {
    height: 80px;
    background-color: #FFFFFF;
    display: inline-flex;
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 1;
    box-shadow: 0px 0.5px 10px #000000;
}

.site-header-fill {
    height: 80px;
}

.site-logo-container {
    height: 60px;
    margin-left: 20px;
    margin-right: auto;
    margin-top: 10px;
    margin-bottom: 10px;
    display: block;
    float: left;
}

.site-logo {
    height: 60px;
    width: auto;
    float: left;
}

.site-nav-action-container {
    height: 50px;
    width: 50px;
    max-width: 50px;
    margin-left: 10px;
    margin-right: 10px;
    margin-top: 15px;
    margin-bottom: 15px;
    display: block;
    float: right;
    text-align: right;
}

.site-nav {
    height: 100%;
    left: 0px;
    position: fixed;
    top: 0px;
    width: 100%;
    background: #3399ff;
    z-index: 2;
    display: none;
}

.site-nav.active {
    display: block;
}

.site-nav-content {
    width: 20%;
    position: absolute;
    left: 50%;
    top: 50%;
    -webkit-transform: translate(-50%, -50%);
    transform: translate(-50%, -50%);
}

@media only screen and (max-width: 500px) {
.site-nav-content {
    width: auto;
    position: absolute;
    left: 50%;
    top: 50%;
    -webkit-transform: translate(-50%, -50%);
    transform: translate(-50%, -50%);
}
}

.site-nav-pages {
    text-align:center;
}

.nav-action {
    height: 50px;
    width: 50px;
}

.pagefill {
  display: block;
  with: 50%;
  height: 2000px;
  background-color: #000000;
  margin: auto;
  margin-top: 100px;
 }
<div class="site-header ">
   <div class="site-logo-container">
      <img class="site-logo" src="https://via.placeholder.com/1000x300" alt="Logo">
   </div>
   <div class="site-nav-action-container">
      <button class="nav-action">
         <p>☰</p>
      </button>
   </div>
</div>
<div class="site-nav">
   <div class="site-nav-action-container">
      <button class="nav-action">
         <p>×</p>
      </button>
   </div>
   <div class="site-nav-content">
      <div class="site-nav-pages">
         <p>Page 1</p>
         <p>Page 2</p>
         <p>Page 3</p>
         <p>Page 4</p>
         <p>Page 5</p>
      </div>
   </div>
</div>


   <div class="pagefill"></div>
 

EDIT

Adding this code seems to solve the problem, but the challenge lies in removing the active class when the navigation is closed. Additionally, the position and overflow-y elements should also be included in the main body class. This solution is promising, but needs refinement.

body.active, html{
    width: 100vw;
    position: fixed !important;
    overflow-y: scroll !important;
}

Answer №1

When the class site-nav is set to 'active', I have included the fixed position for the body element to prevent scrolling when the navigation menu (nav) is activated.

const navButtons = document.querySelectorAll('button.nav-action');
const siteNav = document.querySelector('.site-nav');

function handleButtonClick(event) {
  siteNav.classList.toggle('active');
  if(siteNav.classList.contains('active')){
    document.body.style.position = 'fixed'
  }else{
    document.body.style.position = 'static'
  }
}

navButtons.forEach(button => button.addEventListener('click', handleButtonClick));
.site-header {
    height: 80px;
    background-color: #FFFFFF;
    display: inline-flex;
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 1;
    box-shadow: 0px 0.5px 10px #000000;
}

.site-header-fill {
    height: 80px;
}
/* more CSS code goes here */
<div class="site-header ">
   <div class="site-logo-container">
      <img class="site-logo" src="https://via.placeholder.com/1000x300" alt="Logo">
   </div>
   <div class="site-nav-action-container">
      <button class="nav-action">
         <p>☰</p>
      </button>
   </div>
</div>
<div class="site-nav">
<!-- HTML markup for site navigation -->

Answer №2

Alright, here's the solution to your issue. I managed to tackle the problem by utilizing the window.scroll() method along with the onscroll event listener on the window object. Essentially, I'm checking if the siteNav element has an active class, and if it does, I'm adding an event listener to the window. This listener ensures that whenever the window is scrolled, the scroll position remains at the top using window.scroll(0,0).

const navButtons = document.querySelectorAll('button.nav-action');
const siteNav = document.querySelector('.site-nav');

function disableScroll() {
  window.scroll(0,0);
}

function onClick(event) {
  siteNav.classList.toggle('active');
  
  if (siteNav.classList.contains('active')) {
    document.body.classList.add('active');
    window.addEventListener('scroll', disableScroll);
  } else {
    document.body.classList.remove('active');
    window.removeEventListener('scroll', disableScroll);
  }
}

navButtons.forEach((button) => button.addEventListener('click', onClick));
   
  /* Your CSS styles go here */  
<div>
   <p>Your HTML code goes here</p>
</div>

Answer №3

Here is a potential solution for you:

Check out this CodePen

I made some modifications to the JavaScript code as follows:

   var pf = document.body.querySelector('.pagefill'); // added
   function onClick(event) {
   siteNav.classList.toggle('active');
   siteNav.style.overflowY = "scroll"; // added
   pf.classList.toggle('pf-height'); // added
 }

Additionally, I introduced a new CSS class for the div with the .pagefill class:

  .pf-height {
      height: 0;
  }

With these adjustments, when you open the navigation menu, it will display a scrollbar without enabling scrolling functionality.

Answer №4

This piece of JavaScript code effectively prevents the page width from shifting when the scrollbar is hidden, ensuring a smooth browsing experience across different browsers with varying scrollbar widths.

function toggleMenu() {
   // save current window width
   let oldWidth = document.documentElement.clientWidth;

   // toggle CSS class to hide scrollbar
   document.body.classList.toggle('MenuOpen');

   // get new window width after hiding scrollbar
   let newWidth = document.documentElement.clientWidth;

   // calculate scrollbar width difference
   let scrollbarWidth = Math.max(0, newWidth - oldWidth);
   document.body.style.marginRight = `${scrollbarWidth}px`;
}

To complement the JavaScript, here's some CSS:

html {
    background-color: #e6e6e6; /* customized color for faux scrollbar */
}

body.MenuOpen {
   overflow: hidden;
}

Answer №5

If you want to prevent scrolling on the page, simply modify the overflow property to hidden like so:

html{
    overflow: hidden; // stops scrolling
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

I'm having trouble getting my object to display using ng-repeat in Angular. Can anyone help me understand what I'm missing?

My goal was to add an object to an array upon clicking an event, which I successfully achieved. However, the objects are not displaying in the ng-repeat as ordered. Can you help me figure out what's missing? angular.module('app', []); an ...

Transforming a two-column text document into a set of key-value pairs

Recently, I've been diving into the world of Node.js and Express. My current challenge involves converting a text file into key-value pairs. The approach I'm taking with my staircase program is as follows: https://i.sstatic.net/GPs200IQ.png Th ...

Include a suffix after the user's input in a Material UI TextField

I need to implement a TextField element that displays the entered value followed by an Input Adornment. Can I have the percentage sign (%) appear after the entered value instead of at the end of the input? Currently, the percentage sign (%) appears at the ...

What could be causing this Cloud Function to be triggered multiple times by an Android HTTP request?

A scenario in my Android app involves sending a POST request to an HTTP triggered Cloud Function. The issue arises when Firebase registers the event twice on the Firebase console even though the function is called only once. I have ensured that the button ...

If the user inputs any text, Jquery will respond accordingly; otherwise,

I have a text field that is populated from a database, but if a user decides to change the value, I need to use that new value in a calculation. $('#ecost input.ecost').keyup(function(){ if (!isNaN(this.value) && this.value.length != ...

Maximizing engagement with Mapbox markers

I successfully integrated markers into our mapbox, but I am still curious about how to make them clickable. Can anyone provide guidance on this? Here's the code snippet that I have: <style> /* * Unlike other icons, you can style `L.divIcon` w ...

Issues with implementing Bootstrap 4 navbar on a Rails 5 application

I'm currently in the process of transitioning my static HTML/CSS/JS website to a Rails application. Using Bootstrap 4, I had all the functionality and CSS classes working perfectly on the static site. However, after the migration to the Ruby app, the ...

The JS variable text consistently displays as undefined

I have come across multiple posts on this topic, but none of them seem to be getting through to me or they are slightly different. This issue has been causing me confusion for quite some time. Despite my efforts to find a solution, I am met with conflicti ...

Creating a JavaScript function to display an object on top of a background image

I am in the process of designing a program that mimics Guitar Hero, where red circles appear over an image of a violin when specific key presses are detected. However, I am encountering difficulties with making the circles appear on top of the image even ...

Sending an image dynamically as a prop to a child component

Within my parent component, I retrieve an object from an API which I later enhance with an image as a key/value pair. Subsequently, I pass this modified object to a child component for rendering. In order to accomplish this, I referred to the following pos ...

Tips for transferring data to a different webpage while ensuring that dynamic elements remain active

Is There a Solution to Making Dynamic Elements Persist After Page Load and Transfer Data to the Next Page? I'm struggling with adding a new row that includes both a checkbox and textbox. I've been using the Clone() method to generate a new row, ...

Tips on dividing and recycling mongodb connection in Node.js

I am currently troubleshooting the connection to MongoDB using Node.js. The code I have in a file named mongodb.js is as follows: const mongoClient = require('mongodb').MongoClient; const env = process.env.NODE_ENV || 'development'; co ...

Check to see if the ContentEditable div is currently focused

I'm struggling to determine if a contenteditable div has focus with my current code. Here is what I have so far: if ($("#journal-content:focus")) { alert("Has Focus"); } else { alert("Doesn't Have Focus"); } The issue I'm encounter ...

The "truth" parameter within the xmlHttpRequest .open() function

After referencing MDN, it mentioned that by default, the JavaScript function will keep running until the server response is received. This is essentially what AJAX is all about - Asynchronous JavaScript and XML. Even though I have some experience with A ...

A pair of areas within the content that can be scrolled using both the vertical and horizontal scrollbars of the browser

Can a webpage be created to resemble the layout of this image: I have three specific goals in mind: The first content should only scroll vertically. The second content should only scroll horizontally. It must utilize only browser scrollbars. p.s. It wo ...

Top tips for utilizing numerous XMLHttpRequests efficiently

I am attempting to retrieve 8 JSON objects from 8 different URLs. I have stored the query string that needs to be modified in an Array, and I am looping through it using a for loop. Below is my code: var index = ["ESL_SC2", "OgamingSC2", "cretetion", "fre ...

Building a Form Component within a Table Using ReactJS

I am trying to embed an HTML Form inside a Table. The code I currently have is shown below: render() { return ( <form className="ui form"> <tbody> <tr> <td classN ...

Instructions for transferring an object from a list box with Selenium WebDriver

My webpage has 2 list boxes, one on the left and one on the right, with transfer arrows. To move an item from the left list box to the right side, I need to select it from the left list and click on the arrow. I attempted to write the code below but it is ...

Is there a way for me to have Next.Js automatically download and serve all the external assets on my website?

Currently, I have been putting together a portfolio using headless WordPress and NextJs. To retrieve data from the GraphQl endpoint, I created my own functions which are working perfectly fine. However, my issue lies with media files such as images and pdf ...

Animating the height of a div using nested div elements

Below is the code snippet provided: https://jsfiddle.net/wc48jvgt/69/ The situation involves a div with a horizontal layout named #cleaning_card_1, containing embedded divs that act as borders, and a vertical div called #cleaning_card_right_1 with a neste ...