保持滚动条可见,但在导航菜单打开时禁用

3
我有一个导航菜单已经可以使用,但是当它显示在其他内容之上时,页面仍然可以滚动。按钮的位置与页面相同,如果隐藏滚动条,页面会跳动太多。当活动类处于激活状态时,我想要禁用主体上的滚动条。我尝试在body上使用CSS position: fixed; overflow-y:scroll,但这会添加双重滚动,并且不总是恢复原状。
我希望JS可以修改以在导航打开时保持滚动条存在但不可滚动,但我不确定如何以可行的方式解决此问题。

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>
 

编辑

加入这个似乎可以解决问题,但是问题在于当导航关闭时需要去除活动类(active class)。同时,位置和overflow-y元素也需要在主体类中,但是这已经接近了解决方案。

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

2
site-nav 拥有类名为 'active' 时,我会在 body 上添加 固定定位的位置,以避免启用 nav 时发生滚动。

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>
 


1
+1 对我来说是新知识,我以为将 overflow-y: none 应用于 body 是唯一的方法。谢谢! - Hanz
这并没有解决移位的问题。我在我的问题中提到过我已经尝试过了。我特别需要滚动条保持可见,但在类处于活动状态时被禁用,以便按钮保持在原位。 - learningtoanimate

1

所以,这是你需要的。我通过使用 window.scroll()onscroll 事件监听器在 window 上解决了你的问题,我只是检查 siteNav 是否有活动类,如果有,则向 window 添加一个事件监听器,如果滚动,我将滚动保持在顶部,使用 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>
 


到目前为止,你的答案是最接近的。我在解决我的问题时已经接近了。我只需要在打开时将一个活动类附加到body,因为使用你的答案时滚动条仍然可见,这很令人困惑。需要添加 body.active, html{ width: 100vw; position: fixed !important; overflow-y: scroll !important; },这将保留整个滚动条但不包括实际的滚动句柄。 - learningtoanimate
我已经编辑了答案,这回答了你的问题吗? - soraku02
非常接近了。我希望箭头保留,就像我所做的测试一样。 - learningtoanimate

0

我不确定这是否是您想要的,但我希望是:

CodePen

我将JS更改为以下内容:

   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
 }

并为具有.pagefill类的div创建了这个新类:

  .pf-height {
      height: 0;
  }

通过这个更改,如果您打开导航,它将具有滚动条,但没有可滚动的功能。


嘿,这很接近了,但是pagefill只是为了给出滚动的示例,所以滚动条在那里。我宁愿将一个active类添加到body中,这样可以工作,但我需要在body上设置替代方案,以便仍然可以滚动。 - learningtoanimate

0
这段 JavaScript 代码可以防止页面在滚动条隐藏时宽度跳动。在任何浏览器中都能很好地工作,无论其滚动条的宽度如何。
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`;
}

...还有一些CSS:

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

body.MenuOpen {
   overflow: hidden;
}

-1
要使页面不可滚动,您只需将属性overflow更改为hidden
body{
    overflow: hidden; // to prevent scrolling
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接