只是禁用滚动不隐藏它?

时间:2012-01-02 14:01:46

标签: javascript jquery html css

我正在尝试在使用灯箱时禁用父级的html / body滚动条。这里的主要词是禁用。我希望用overflow: hidden;隐藏它。

原因是overflow: hidden使网站跳转并占据滚动区域。

我想知道是否可以在显示滚动条时禁用滚动条。

21 个答案:

答案 0 :(得分:149)

如果覆盖层下的页面可以“固定”在顶部,当您打开覆盖图时可以设置

body { position: fixed; overflow-y:scroll }

您仍然应该看到正确的滚动条,但内容不可滚动。关闭叠加层时,只需使用

还原这些属性
body { position: static; overflow-y:auto }

我之所以提出这种方式只是因为你不需要改变任何滚动事件

<强>更新

您还可以稍微改进一下:如果您在图层打开之前通过javascript获取document.documentElement.scrollTop属性,则可以动态地将该值指定为body元素的top属性:使用此方法无论您是在顶部还是已经滚动,页面都会代替它。

<强>的CSS

.noscroll { position: fixed; overflow-y:scroll }

<强> JS

$('body').css('top', -(document.documentElement.scrollTop) + 'px')
         .addClass('noscroll');

答案 1 :(得分:74)

对所选解决方案的四点补充:

  1. 将'noscroll'应用于 html而不是身体以防止IE中出现双滚动条
  2. 在添加'noscroll'课程之前,检查是否实际存在滚动条。否则,该站点也将被新的非滚动滚动条跳过。
  3. 要保留任何可能的 scrollTop ,以便整个页面不会返回到顶部(例如Fabrizio的更新,但您需要在添加'noscroll'类之前获取值)
  4. 并非所有浏览器都以与http://help.dottoro.com/ljnvjiow.php
  5. 中记录的方式相同的方式处理scrollTop

    似乎适用于大多数浏览器的完整解决方案:

    <强> CSS

    html.noscroll {
        position: fixed; 
        overflow-y: scroll;
        width: 100%;
    }
    

    停用滚动

    if ($(document).height() > $(window).height()) {
         var scrollTop = ($('html').scrollTop()) ? $('html').scrollTop() : $('body').scrollTop(); // Works for Chrome, Firefox, IE...
         $('html').addClass('noscroll').css('top',-scrollTop);         
    }
    

    启用滚动

    var scrollTop = parseInt($('html').css('top'));
    $('html').removeClass('noscroll');
    $('html,body').scrollTop(-scrollTop);
    

    感谢Fabrizio和Dejan让我走上了正确的道路,感谢Brodingo the solution to the double scroll bar

答案 2 :(得分:31)

包含jQuery:

禁用

$.fn.disableScroll = function() {
    window.oldScrollPos = $(window).scrollTop();

    $(window).on('scroll.scrolldisabler',function ( event ) {
       $(window).scrollTop( window.oldScrollPos );
       event.preventDefault();
    });
};

使

$.fn.enableScroll = function() {
    $(window).off('scroll.scrolldisabler');
};

使用

//disable
$("#selector").disableScroll();
//enable
$("#selector").enableScroll();

答案 3 :(得分:8)

这对我来说非常好....

// disable scrolling
$('body').bind('mousewheel touchmove', lockScroll);

// enable scrolling
$('body').unbind('mousewheel touchmove', lockScroll);


// lock window scrolling
function lockScroll(e) {
    e.preventDefault();
}

只需在你要锁定滚动的时候用这两行代码包装。

e.g。

$('button').on('click', function() {
     $('body').bind('mousewheel touchmove', lockScroll);
});

答案 4 :(得分:7)

您无法禁用滚动事件,但您可以禁用导致滚动的相关操作,例如鼠标滚轮和touchmove:

$('body').on('mousewheel touchmove', function(e) {
      e.preventDefault();
});

答案 5 :(得分:6)

我是OP

在fcalderan回答的帮助下,我能够形成一个解决方案。我将解决方案留在这里,因为它清楚地说明了如何使用它,并添加了一个非常关键的细节,width: 100%;

我添加了这个类

body.noscroll
{
    position: fixed; 
    overflow-y: scroll;
    width: 100%;
}

这对我有用,我正在使用Fancyapp。

答案 6 :(得分:3)

或者,您可以使用overflow: hidden隐藏正文的滚动条并同时设置边距,以便内容不会跳转:

let marginRightPx = 0;
if(window.getComputedStyle) {
    let bodyStyle = window.getComputedStyle(document.body);
    if(bodyStyle) {
        marginRightPx = parseInt(bodyStyle.marginRight, 10);
    }
}

let scrollbarWidthPx = window.innerWidth - document.body.clientWidth;
Object.assign(document.body.style, {
    overflow: 'hidden',
    marginRight: `${marginRightPx + scrollbarWidthPx}px`
});

然后,您可以向页面添加禁用的滚动条以填补空白:

textarea {
  overflow-y: scroll;
  overflow-x: hidden;
  width: 11px;
  outline: none;
  resize: none;
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  border: 0;
}
<textarea></textarea>

我为自己的灯箱实现做了这个。到目前为止似乎运作良好。

答案 7 :(得分:2)

这是我们采用的解决方案。打开叠加层时,只需保存滚动位置,只要用户尝试滚动页面,就可以回滚到保存的位置,并在叠加层关闭时关闭监听器。

它在IE上有点跳跃,但就像Firefox / Chrome上的魅力一样。

&#13;
&#13;
var body = $("body"),
  overlay = $("#overlay"),
  overlayShown = false,
  overlayScrollListener = null,
  overlaySavedScrollTop = 0,
  overlaySavedScrollLeft = 0;

function showOverlay() {
  overlayShown = true;

  // Show overlay
  overlay.addClass("overlay-shown");

  // Save scroll position
  overlaySavedScrollTop = body.scrollTop();
  overlaySavedScrollLeft = body.scrollLeft();

  // Listen for scroll event
  overlayScrollListener = body.scroll(function() {
    // Scroll back to saved position
    body.scrollTop(overlaySavedScrollTop);
    body.scrollLeft(overlaySavedScrollLeft);
  });
}

function hideOverlay() {
  overlayShown = false;

  // Hide overlay
  overlay.removeClass("overlay-shown");

  // Turn scroll listener off
  if (overlayScrollListener) {
    overlayScrollListener.off();
    overlayScrollListener = null;
  }
}

// Click toggles overlay
$(window).click(function() {
  if (!overlayShown) {
    showOverlay();
  } else {
    hideOverlay();
  }
});
&#13;
/* Required */
html, body { margin: 0; padding: 0; height: 100%; background: #fff; }
html { overflow: hidden; }
body { overflow-y: scroll; }

/* Just for looks */
.spacer { height: 300%; background: orange; background: linear-gradient(#ff0, #f0f); }
.overlay { position: fixed; top: 20px; bottom: 20px; left: 20px; right: 20px; z-index: -1; background: #fff; box-shadow: 0 0 5px rgba(0, 0, 0, .3); overflow: auto; }
.overlay .spacer { background: linear-gradient(#88f, #0ff); }
.overlay-shown { z-index: 1; }
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

<h1>Top of page</h1>
<p>Click to toggle overlay. (This is only scrollable when overlay is <em>not</em> open.)</p>
<div class="spacer"></div>
<h1>Bottom of page</h1>
<div id="overlay" class="overlay">
  <h1>Top of overlay</h1>
  <p>Click to toggle overlay. (Containing page is no longer scrollable, but this is.)</p>
  <div class="spacer"></div>
  <h1>Bottom of overlay</h1>
</div>
&#13;
&#13;
&#13;

答案 8 :(得分:1)

我注意到 YouTube 网站正是这样做的。因此,通过稍微检查一下,我已经能够确定他们正在使用 @polymer/iron-overlay-behavior,幸运的是,它可以在 Web 组件/聚合物之外相当不显眼地使用:

import {
    pushScrollLock,
    removeScrollLock,
} from '@polymer/iron-overlay-behavior/iron-scroll-manager';

// lock scroll everywhere except scrollElement
pushScrollLock(scrollElement);

// restore scrolling
removeScrollLock(scrollElement);
  • 允许在所选元素中滚动
  • 不会以任何方式弄乱样式
  • 在 YouTube 网站上经过实战测试

这似乎是一个成熟的解决方案,而且肯定是我能找到的最好的解决方案。这个包有点重,但我想当只导入 iron-scroll-manager 时,其中大部分都没有捆绑。

干杯

答案 9 :(得分:1)

我遇到了类似的问题:一个左手菜单,当它出现时,会阻止滚动。高度设置为100vh后,滚动条消失,内容突然向右移动。

因此,如果您不介意保持滚动条的启用(但将窗口设置为全高,以便它实际上不会在任何地方滚动),那么另一种可能性是设置一个微小的底部边距,这将保持滚动条显示:< / p>

body {
    height: 100vh;
    overflow: hidden;
    margin: 0 0 1px;
}

答案 10 :(得分:0)

<div id="lightbox">位于<body>元素内,因此当您滚动灯箱时,您还会滚动正文。解决方案是不将<body>元素延伸超过100%,将长内容放在另一个div元素中,并在需要时使用div元素添加滚动条overflow: auto元素}。

&#13;
&#13;
html {
  height: 100%
}
body {
  margin: 0;
  height: 100%
}
#content {
  height: 100%;
  overflow: auto;
}
#lightbox {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
}
&#13;
<html>
  <body>
    <div id="content">much content</div>
    <div id="lightbox">lightbox<div>
  </body>
</html>
&#13;
&#13;
&#13;

现在,滚动灯箱(以及body)也没有效果,因为正文不超过屏幕高度的100%。

答案 11 :(得分:0)

我喜欢坚持&#34;溢出:隐藏&#34;方法,只需添加填充权限等于滚动条宽度。

获取滚动条宽度函数,lostsource

function getScrollbarWidth() {
    var outer = document.createElement("div");
    outer.style.visibility = "hidden";
    outer.style.width = "100px";
    outer.style.msOverflowStyle = "scrollbar"; // needed for WinJS apps

    document.body.appendChild(outer);

    var widthNoScroll = outer.offsetWidth;
    // force scrollbars
    outer.style.overflow = "scroll";

    // add innerdiv
    var inner = document.createElement("div");
    inner.style.width = "100%";
    outer.appendChild(inner);        

    var widthWithScroll = inner.offsetWidth;

    // remove divs
    outer.parentNode.removeChild(outer);

    return widthNoScroll - widthWithScroll;
}

显示叠加层时,添加&#34; noscroll&#34; class to html并将padding-right添加到body:

$(html).addClass("noscroll");
$(body).css("paddingRight", getScrollbarWidth() + "px");

隐藏时,删除类和填充:

$(html).removeClass("noscroll");
$(body).css("paddingRight", 0);

noscroll样式就是这样:

.noscroll { overflow: hidden; }

请注意,如果您有任何位置:固定的元素,您还需要将填充添加到这些元素。

答案 12 :(得分:0)

原油但工作方式是强制滚动回到顶部,从而有效地禁用滚动:

var _stopScroll = false;
window.onload = function(event) {
    document.onscroll = function(ev) {
        if (_stopScroll) {
            document.body.scrollTop = "0px";
        }
    }
};

当您打开灯箱时抬起旗帜,关闭旗帜时,请降低旗帜。

Live test case

答案 13 :(得分:0)

你可以保持溢出:隐藏但手动管理滚动位置:

在显示实际滚动位置的跟踪之前:

var scroll = [$(document).scrollTop(),$(document).scrollLeft()];
//show your lightbox and then reapply scroll position
$(document).scrollTop(scroll[0]).scrollLeft(scroll[1]);

它应该有用

答案 14 :(得分:0)

在基于html或body的标签上显示模式/灯箱时,所有基于javascript的模式/灯箱系统都会溢出。

当显示灯箱时,js会推送隐藏在html或body标签上的溢出。 隐藏灯箱后,有些会删除隐藏的内容,而另一些会在html或body标签上推送自动溢出。

在Mac上工作的开发人员看不到滚动条的问题。

只需用未设置的内容替换隐藏的内容,就不会看到内容在删除滚动条的方式下滑动。

灯箱打开/显示:

<html style="overflow: unset;"></html>

灯箱关闭/隐藏:

<html style="overflow: auto;"></html>

答案 15 :(得分:0)

如果顶层下方的页面可以在顶部“固定”,则打开叠加层时可以设置

.disableScroll { position: fixed; overflow-y:scroll }

将此类提供给可滚动的正文,您仍应看到右侧的滚动条,但内容不可滚动。

要保持页面的位置,请在jquery中执行

$('body').css('top', - ($(window).scrollTop()) + 'px').addClass('disableScroll');

当您关闭叠加层时,只需还原这些属性即可

var top = $('body').position().top;
$('body').removeClass('disableScroll').css('top', 0).scrollTop(Math.abs(top));

我之所以这样提议只是因为您不需要更改任何滚动事件

答案 16 :(得分:0)

这将通过保存滚动位置并在启用滚动功能后将其恢复来阻止视口跳到顶部。

CSS

.no-scroll{
  position: fixed; 
  width:100%;
  min-height:100vh;
  top:0;
  left:0;
  overflow-y:scroll!important;
}

JS

var scrollTopPostion = 0;

function scroll_pause(){
  scrollTopPostion = $(window).scrollTop();
  $("body").addClass("no-scroll").css({"top":-1*scrollTopPostion+"px"});
}

function scroll_resume(){
  $("body").removeClass("no-scroll").removeAttr("style");
  $(window).scrollTop(scrollTopPostion);
}

现在您需要做的就是调用函数

$(document).on("click","#DISABLEelementID",function(){
   scroll_pause();
});

$(document).on("click","#ENABLEelementID",function(){
   scroll_resume();
});

答案 17 :(得分:0)

另一种解决方法是在移除正文滚动时摆脱固定模式上的内容跳转:标准化页面宽度:

body {width: 100vw; overflow-x: hidden;}

然后,您可以固定位置播放或溢出:模式打开时隐藏在身体上。但是它将隐藏水平滚动条-通常在响应式网站上不需要。

答案 18 :(得分:0)

position: fixed;解决方案有一个缺点-应用此样式时,页面跳至顶部。 Angular的“材质对话框”是一个很好的解决方案,他们通过将定位应用于html元素来伪造滚动位置。

以下是我修改后的仅用于垂直滚动的算法。完全按照相同的方式完成向左滚动滚动。

// This class applies the following styles:
// position: fixed;
// overflow-y: scroll;
// width: 100%;
const NO_SCROLL_CLASS = "bp-no-scroll";

const coerceCssPixelValue = value => {
  if (value == null) {
    return "";
  }

  return typeof value === "string" ? value : `${value}px`;
};

export const blockScroll = () => {
  const html = document.documentElement;
  const documentRect = html.getBoundingClientRect();
  const { body } = document;

  // Cache the current scroll position to be restored later.
  const cachedScrollPosition =
    -documentRect.top || body.scrollTop || window.scrollY || document.scrollTop || 0;

  // Cache the current inline `top` value in case the user has set it.
  const cachedHTMLTop = html.style.top || "";

  // Using `html` instead of `body`, because `body` may have a user agent margin,
  // whereas `html` is guaranteed not to have one.
  html.style.top = coerceCssPixelValue(-cachedScrollPosition);

  // Set the magic class.
  html.classList.add(NO_SCROLL_CLASS);

  // Return a function to remove the scroll block.
  return () => {
    const htmlStyle = html.style;
    const bodyStyle = body.style;

    // We will need to seamlessly restore the original scroll position using
    // `window.scroll`. To do that we will change the scroll behavior to `auto`.
    // Here we cache the current scroll behavior to restore it later.
    const previousHtmlScrollBehavior = htmlStyle.scrollBehavior || "";
    const previousBodyScrollBehavior = bodyStyle.scrollBehavior || "";

    // Restore the original inline `top` value.
    htmlStyle.top = cachedHTMLTop;

    // Remove the magic class.
    html.classList.remove(NO_SCROLL_CLASS);

    // Disable user-defined smooth scrolling temporarily while we restore the scroll position.
    htmlStyle.scrollBehavior = bodyStyle.scrollBehavior = "auto";

    // Restore the original scroll position.
    window.scroll({
      top: cachedScrollPosition.top
    });

    // Restore the original scroll behavior.
    htmlStyle.scrollBehavior = previousHtmlScrollBehavior;
    bodyStyle.scrollBehavior = previousBodyScrollBehavior;
  };
};

逻辑很简单,如果您不关心某些极端情况,则可以进一步简化。例如,这就是我所使用的:

export const blockScroll = () => {
  const html = document.documentElement;
  const documentRect = html.getBoundingClientRect();
  const { body } = document;
  const screenHeight = window.innerHeight;

  // Only do the magic if document is scrollable
  if (documentRect.height > screenHeight) {
    const cachedScrollPosition =
      -documentRect.top || body.scrollTop || window.scrollY || document.scrollTop || 0;

    html.style.top = coerceCssPixelValue(-cachedScrollPosition);

    html.classList.add(NO_SCROLL_CLASS);

    return () => {
      html.classList.remove(NO_SCROLL_CLASS);

      window.scroll({
        top: cachedScrollPosition,
        behavior: "auto"
      });
    };
  }
};

答案 19 :(得分:0)

我做了这个函数,用JS解决了这个问题。 此原则可以轻松扩展和定制,这对我来说是一个很大的优势。

使用此js DOM API函数:

const handleWheelScroll = (element) => (event) => {
  if (!element) {
    throw Error("Element for scroll was not found");
  }
  const { deltaY } = event;
  const { clientHeight, scrollTop, scrollHeight } = element;
  if (deltaY < 0) {
    if (-deltaY > scrollTop) {
      element.scrollBy({
        top: -scrollTop,
        behavior: "smooth",
      });
      event.stopPropagation();
      event.preventDefault();
    }
    return;
  }

  if (deltaY > scrollHeight - clientHeight - scrollTop) {
    element.scrollBy({
      top: scrollHeight - clientHeight - scrollTop,
      behavior: "smooth",
    });
    event.stopPropagation();
    event.preventDefault();
    return;
  }
};

简而言之,如果滚动将滚动给定元素(要滚动的元素)之外的其他内容,则此函数将停止事件传播和默认行为。

然后您就可以像这样钩住和取消钩住了:

const wheelEventHandler = handleWheelScroll(elementToScrollIn);

window.addEventListener("wheel", wheelEventHandler, {
    passive: false,
});

window.removeEventListener("wheel", wheelEventHandler);

请注意,它是一个高阶函数,因此您必须保留对给定实例的引用。

我在jQuery鼠标挂钩事件中钩住了addEventListener部分,在jQuery的鼠标离开事件中钩住了removeEventListener,但是您可以随意使用它。

答案 20 :(得分:-1)

您可以使用Javascript:

// Classic JS
window.onscroll = function(ev) {
  ev.preventDefault();
}

// jQuery
$(window).scroll(function(ev) {
  ev.preventDefault();
}

然后在灯箱关闭时禁用它。

但是如果你的灯箱包含一个滚动条,你将无法在它打开时滚动。这是因为window同时包含body#lightbox。 所以你必须使用如下的架构:

<body>
  <div id="global"></div>
  <div id="lightbox"></div>
</body>

然后仅在onscroll上应用#global事件。