防止正文滚动但允许叠加滚动

时间:2012-02-14 16:13:47

标签: css overlay lightbox

我一直在寻找一种“灯箱”型解决方案,允许这样但尚未找到一个(请提示,如果你知道的话)。

我正在尝试重新创建的行为就像您在点击图片时在Pinterest看到的那样。叠加层是可滚动的(,因为整个叠加层像页面顶部的页面一样向上移动)但是叠加层后面的 是固定的。

我尝试使用CSS(即整个页面顶部的div叠加层和overflow: hidden 的正文来创建此内容,但它不会阻止{ {1}}可滚动。

如何防止正文/页面滚动但是在全屏容器内滚动?

19 个答案:

答案 0 :(得分:560)

<强>理论

查看pinterest网站的当前实施(将来可能会更改),当您打开叠加层时,noscroll类会应用于body元素并设置overflow: hidden ,因此body不再可滚动。

叠加层(即时创建或已在页面内部创建并通过display: block显示,没有区别)有position : fixedoverflow-y: scroll,{{1} },topleftright属性设置为bottom:此样式使叠加层填充整个视口。

叠加层中的0只是在div中,然后您看到的垂直滚动条与该元素相关。因此,内容是可滚动的,但叠加层仍然是固定的。

当你关闭缩放时,你隐藏了叠加层(通过position: static),然后你也可以通过javascript(或者只是里面的内容,它取决于你如何注入它)完全删除它。

作为最后一步,您还必须将display: none类删除到noscroll(以便溢出属性返回其初始值)


<强>代码

  

Codepen Example

(它可以通过更改叠加层的body属性来显示和隐藏它并增加其可访问性。

<强>标记
(打开按钮)

aria-hidden

(叠加和关闭按钮)

<button type="button" class="open-overlay">OPEN LAYER</button>

<强> CSS

<section class="overlay" aria-hidden="true">
  <div>
    <h2>Hello, I'm the overlayer</h2>
    ...   
    <button type="button" class="close-overlay">CLOSE LAYER</button>
  </div>
</section>

Javascript (vanilla-JS)

.noscroll { 
  overflow: hidden;
}

.overlay { 
   position: fixed; 
   overflow-y: scroll;
   top: 0; right: 0; bottom: 0; left: 0; }

[aria-hidden="true"]  { display: none; }
[aria-hidden="false"] { display: block; }

最后,这是另一个示例,其中通过应用于var body = document.body, overlay = document.querySelector('.overlay'), overlayBtts = document.querySelectorAll('button[class$="overlay"]'); [].forEach.call(overlayBtts, function(btt) { btt.addEventListener('click', function() { /* Detect the button class name */ var overlayOpen = this.className === 'open-overlay'; /* Toggle the aria-hidden state on the overlay and the no-scroll class on the body */ overlay.setAttribute('aria-hidden', !overlayOpen); body.classList.toggle('noscroll', overlayOpen); /* On some mobile browser when the overlay was previously opened and scrolled, if you open it again it doesn't reset its scrollTop property */ overlay.scrollTop = 0; }, false); }); 属性的CSS transition以淡入效果打开叠加层。此外,还应用opacity以避免在滚动条消失时对基础文本进行重排。

  

Codepen Example (fade)

<强> CSS

padding-right

答案 1 :(得分:69)

如果你想防止在ios上过度滚动,你可以添加固定在.noscroll类的位置

body.noscroll{
    position:fixed;
    overflow:hidden;
}

答案 2 :(得分:37)

请勿在{{1​​}}上使用overflow: hidden;。它会自动将所有内容滚动到顶部。也不需要JavaScript。利用body。该解决方案甚至适用于移动Safari:

HTML结构

overflow: auto;

定型

<div class="overlay">
    <div class="overlay-content"></div>
</div>

<div class="background-content">
    lengthy content here
</div>

查看演示here和源代码here

<强>更新

对于想要键盘空格键,页面向上/向下工作的人:你需要专注于叠加层,例如点击它,或者在.overlay{ position: fixed; top: 0px; left: 0px; right: 0px; bottom: 0px; background-color: rgba(0, 0, 0, 0.8); .overlay-content { height: 100%; overflow: scroll; } } .background-content{ height: 100%; overflow: auto; } 的这一部分响应之前手动JS聚焦它键盘。与覆盖“关闭”时相同,因为它只是将覆盖移动到侧面。除了浏览器,这些只是两个正常的div,它不知道为什么它应该专注于它们中的任何一个。

答案 3 :(得分:30)

值得注意的是,有时在body标签中添加“overflow:hidden”并不能完成这项工作。在这些情况下,您还必须将属性添加到html标记中。

html, body {
    overflow: hidden;
}

答案 4 :(得分:26)

大多数解决方案都存在不保留滚动位置的问题,所以我看看Facebook是如何做到这一点的。除了将底层内容设置为position: fixed之外,他们还动态设置顶部以保留滚动位置:

scrollPosition = window.pageYOffset;
mainEl.style.top = -scrollPosition + 'px';

然后,当您再次移除叠加层时,需要重置滚动位置:

window.scrollTo(0, scrollPosition);

我创建了一个示例来演示此解决方案

let overlayShown = false;
let scrollPosition = 0;

document.querySelector('.toggle').addEventListener('click', function() {
  if (overlayShown) {
		showOverlay();
  } else {
    removeOverlay();
  }
  overlayShown = !overlayShown;
});

function showOverlay() {
    scrollPosition = window.pageYOffset;
  	const mainEl = document.querySelector('.main-content');
    mainEl.style.top = -scrollPosition + 'px';
  	document.body.classList.add('show-overlay');
}

function removeOverlay() {
		document.body.classList.remove('show-overlay');
  	window.scrollTo(0, scrollPosition);
    const mainEl = document.querySelector('.main-content');
    mainEl.style.top = 0;
}
.main-content {
  background-image: repeating-linear-gradient( lime, blue 103px);
  width: 100%;
  height: 200vh;
}

.show-overlay .main-content {
  position: fixed;
  left: 0;
  right: 0;
  overflow-y: scroll; /* render disabled scroll bar to keep the same width */
}

.overlay {
  display: none;
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.3);
  overflow: auto;
}

.show-overlay .overlay {
  display: block;
}

.overlay-content {
  margin: 50px;
  background-image: repeating-linear-gradient( grey, grey 20px, black 20px, black 40px);
  height: 120vh;
}

.toggle {
  position: fixed;
  top: 5px;
  left: 15px;
  padding: 10px;
  background: red;
}

/* reset CSS */
body {
  margin: 0;
}
<main class="main-content"></main>

  <div class="overlay">
    <div class="overlay-content"></div>
  </div>
  
  <button class="toggle">Overlay</button>

答案 5 :(得分:23)

overscroll-behavior css属性允许在到达内容的顶部/底部时覆盖浏览器的默认溢出滚动行为。

只需将以下样式添加到叠加层:

.overlay {
   overscroll-behavior: contain;
   ...
}
  

Codepen demo

目前适用于Chrome,Firefox和IE(caniuse

有关详细信息,请查看google developers article

答案 6 :(得分:7)

所选答案是正确的,但有一些限制:

  • 超级辛苦&#34; flings&#34;用手指仍然会在后台滚动<body>
  • 点击模式中的<input>打开虚拟键盘会将所有未来的卷轴定向到<body>

我没有解决第一个问题,但想要了解第二个问题。令人困惑的是,Bootstrap曾经记录过键盘问题,但他们声称它已修复,引用http://output.jsbin.com/cacido/quiet作为修复的一个例子。

事实上,该示例在我的测试中适用于iOS。但是,将其升级到最新的Bootstrap(v4)会破坏它。

为了弄清楚它们之间的区别是什么,我将测试用例减少为不再依赖于Bootstrap,http://codepen.io/WestonThayer/pen/bgZxBG

决定因素很奇怪。避免键盘问题似乎要求background-color 设置在包含模式的根<div> 模式的内容必须嵌套在另一个<div>中,可以设置background-color

要测试它,请取消注释Codepen示例中的以下行:

.modal {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 2;
  display: none;
  overflow: hidden;
  -webkit-overflow-scrolling: touch;
  /* UNCOMMENT TO BREAK */
/*   background-color: white; */
}

答案 7 :(得分:6)

一般来说,如果您希望父项(在这种情况下是正文)在子项(在这种情况下为叠加层)滚动时阻止它滚动,则使子项成为父项的兄弟,以防止滚动事件发生冒泡到父母。如果父项是正文,则需要一个额外的包装元素:

<div id="content">
</div>
<div id="overlay">
</div>

请参阅Scroll particular DIV contents with browser's main scrollbar了解其工作情况。

答案 8 :(得分:4)

对于触摸设备,请尝试在叠加层的包装中添加1px宽,101vh最小高度透明div。然后将-webkit-overflow-scrolling:touch; overflow-y: auto;添加到包装器中。这使得移动游猎可以认为叠加是可滚动的,从而拦截了身体的触摸事件。

这是一个示例页面。在移动版游记中打开:http://www.originalfunction.com/overlay.html

https://gist.github.com/YarGnawh/90e0647f21b5fa78d2f678909673507f

答案 9 :(得分:3)

我发现这个问题试图解决我在Ipad和Iphone上的页面问题 - 当我将固定div显示为弹出图像时,正在滚动。

有些答案很好,但没有一个能解决我的问题。我找到了Christoffer Pettersson的博客文章。在那里提出的解决方案有助于我使用iOS设备的问题,它帮助我滚动背景问题。

Six things I learnt about iOS Safari's rubber band scrolling

因为有人建议我在博客文章中包含主要内容,以防链接过时。

&#34;为了禁用用户可以在&#34;菜单打开的情况下滚动背景页面&#34;,可以通过应用控制哪些元素应该被滚动?一些JavaScript和一个CSS类。

基于此Stackoverflow答案,您可以控制禁用滚动的元素不应该 触发touchmove事件时执行默认的滚动操作。&#34;

 document.ontouchmove = function ( event ) {

    var isTouchMoveAllowed = true, target = event.target;

    while ( target !== null ) {
        if ( target.classList && target.classList.contains( 'disable-scrolling' ) ) {
            isTouchMoveAllowed = false;
            break;
        }
        target = target.parentNode;
    }

    if ( !isTouchMoveAllowed ) {
        event.preventDefault();
    }
};

然后将禁用滚动类放在页面div上:

<div class="page disable-scrolling">

答案 10 :(得分:2)

您可以使用一些“新” css和JQuery轻松地做到这一点。

最初:body {... overflow:auto;} 使用JQuery,您可以在“覆盖”和“主体”之间动态切换。在“身体”上时,使用

body {
   position: static;
   overflow: auto;
}

在“覆盖”时使用

body {
   position: sticky;
   overflow: hidden;
}

jQuery的switch('body'->'overlay'):

$("body").css({"position": "sticky", "overflow": "hidden"});

jQuery的switch('overlay'->'body'):

$("body").css({"position": "static", "overflow": "auto"});

答案 11 :(得分:1)

使用以下HTML:

<body>
  <div class="page">Page content here</div>
  <div class="overlay"></div>
</body>

然后JavaScript拦截并停止滚动:

$(".page").on("touchmove", function(event) {
  event.preventDefault()
});

然后让事情恢复正常:

$(".page").off("touchmove");

答案 12 :(得分:1)

我想添加之前的答案,因为我试图这样做,并且一旦我将身体切换到位置,一些布局就会破坏:修复。为了避免这种情况,我还必须将身体的高度设置为100%:

function onMouseOverOverlay(over){
    document.getElementsByTagName("body")[0].style.overflowY = (over?"hidden":"scroll");
    document.getElementsByTagName("html")[0].style.position = (over?"fixed":"static");
    document.getElementsByTagName("html")[0].style.height = (over?"100%":"auto");
}

答案 13 :(得分:0)

如果要在移动设备/触摸设备上禁用,那么最简单的方法就是使用touch-action: none;

示例:

const app = document.getElementById('app');
const overlay = document.getElementById('overlay');

let body = '';

for (let index = 0; index < 500; index++) {
  body += index + '<br />';
}

app.innerHTML = body;
app.scrollTop = 200;

overlay.innerHTML = body;
* {
  margin: 0;
  padding: 0;
}

html,
body {
  height: 100%;
}

#app {
  background: #f00;
  position: absolute;
  height: 100%;
  width: 100%;
  overflow-y: scroll;
  line-height: 20px;
}

#overlay {
  background: rgba(0,0,0,.5);
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 100%;
  padding: 0 0 0 100px;
  overflow: scroll;
}
<div id='app'></div>
<div id='overlay'></div>

(该示例在Stack Overflow的上下文中不起作用。您需要在独立页面中重新创建它。)

如果您想要停止滚动#app容器,只需添加touch-action: none;

答案 14 :(得分:0)

尝试

var mywindow = $('body'), navbarCollap = $('.navbar-collapse');    
navbarCollap.on('show.bs.collapse', function(x) {
                mywindow.css({visibility: 'hidden'});
                $('body').attr("scroll","no").attr("style", "overflow: hidden");
            });
            navbarCollap.on('hide.bs.collapse', function(x) {
                mywindow.css({visibility: 'visible'});
                $('body').attr("scroll","yes").attr("style", "");
            });

答案 15 :(得分:0)

您要防止的行为称为滚动链接。要禁用它,请设置

6.1.4

在您的CSS叠加层上。

答案 16 :(得分:0)

如果要停止body / html滚动,请添加以下内容

CSS

    html, body {
        height: 100%;
    }

    .overlay{
        position: fixed;
        top: 0px;
        left: 0px;
        right: 0px;
        bottom: 0px;
        background-color: rgba(0, 0, 0, 0.8);

        .overlay-content {
            height: 100%;
            overflow: scroll;
        }
    }

    .background-content{
        height: 100%;
        overflow: auto;
    }

HTML

    <div class="overlay">
        <div class="overlay-content"></div>
    </div>

    <div class="background-content">
        lengthy content here
    </div>

基本上,没有JS就可以做到。

主要思想是添加html / body,高度:100%,溢出:自动。 在叠加层内部,您可以根据需要启用/禁用滚动。

希望这会有所帮助!

答案 17 :(得分:-1)

就我而言,这些解决方案都没有在iPhone(iOS 11.0)上实现。

在我的所有设备上唯一有效的解决方案是这一个 - ios-10-safari-prevent-scrolling-behind-a-fixed-overlay-and-maintain-scroll-position

答案 18 :(得分:-2)

使用以下代码禁用和启用滚动条。

Scroll = (
    function(){
          var x,y;
         function hndlr(){
            window.scrollTo(x,y);
            //return;
          }  
          return {

               disable : function(x1,y1){
                    x = x1;
                    y = y1;
                   if(window.addEventListener){
                       window.addEventListener("scroll",hndlr);
                   } 
                   else{
                        window.attachEvent("onscroll", hndlr);
                   }     

               },
               enable: function(){
                      if(window.removeEventListener){
                         window.removeEventListener("scroll",hndlr);
                      }
                      else{
                        window.detachEvent("onscroll", hndlr);
                      }
               } 

          }
    })();
 //for disabled scroll bar.
Scroll.disable(0,document.body.scrollTop);
//for enabled scroll bar.
Scroll.enable();