learningtoanimate
learningtoanimate

Reputation: 934

Keep scroll visible but disable when nav menu open

I have a nav menu working but the page is still scrollable when that becomes visible over the top of the rest of the content. Because the button is positioned so it's in the same place the page would jump about too much if the scroll bar was hidden. I want to disable the scrollbar on the body when the active class is active. I had tried using CSS position: fixed; overflow-y:scroll on body but this adds double scrolling and doesn't always revert.

I'm hoping the JS can be modified to keep the scrollbar present but not scrollable while the nav is open I'm just not sure how to approach this in a workable way.

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 seems to do the trick but the issue is removing the active class when the nav is closed. The position and overflow-y elements also need to be in the main body class too but this is close.

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

Upvotes: 3

Views: 2079

Answers (5)

mph
mph

Reputation: 878

This JavaScript will prevent the page width from jumping around when the scrollbar is hidden. Works great in any browser, regardless of its scrollbar width.

function toggleMenu() {
   // get width before hiding scrollbar
   let oldWidth = document.documentElement.clientWidth;

   // toggle CSS class that sets overflow to hidden
   document.body.classList.toggle('MenuOpen');

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

   // set margin-right value equal to width of the scrollbar
   let scrollbarWidth = Math.max(0, newWidth - oldWidth);
   document.body.style.marginRight = `${scrollbarWidth}px`;
}

...and some CSS:

html {
    background-color: #e6e6e6; /* color of fake scrollbar */
}

body.MenuOpen {
   overflow: hidden;
}

Upvotes: 0

soraku02
soraku02

Reputation: 340

So, Here's what you need. I solved your problem, by using window.scroll() and onscroll event listener on window, I am just checking if siteNav has active class, if so then I added and an eventListener to window, if it is scrolled, I'm keeping the scroll at top, by 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));
   
  body.active::-webkit-scrollbar{
    background:rgba(150,150,150,.2);
  }
.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>
 

Upvotes: 1

Satyam Mishra
Satyam Mishra

Reputation: 80

To make the page unscrollable you just need to change the property overflow to hidden by :

body{
    overflow: hidden; // to prevent scrolling
}

Upvotes: -1

salar yeganeh
salar yeganeh

Reputation: 43

I'm not sure this is what you want but I hope it is:

CodePen

I changed JS like this:

   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
 }

and created this new class for the div with .pagefill class:

  .pf-height {
      height: 0;
  }

with this change if you open the nav it will have scrollbar but with no scrollable feature

Upvotes: 0

Uchiha Itachi
Uchiha Itachi

Reputation: 119

When site-nav has a class 'active' I added position of fixed to body in order to avoid scrolling when nav is enabled

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

function onClick(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', 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>
 

Upvotes: 2

Related Questions