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

Pot*_*Fro 404 css overlay lightbox

我一直在寻找一个"灯箱"类型的解决方案,允许这个但尚未找到一个(请,如果您知道任何,请建议).

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

我试图用CSS创建它(div在整个页面和主体上面叠加overflow: hidden),但它不会阻止div可滚动.

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

fca*_*ran 593

理论

查看pinterest站点的当前实现(将来可能会更改),当您打开覆盖层时,将一个noscroll类应用于该body元素并overflow: hidden进行设置,因此body不再可滚动.

叠加(上即时或已经在页面内,并通过可见创建display: block,它使没有区别)有position : fixedoverflow-y: scroll,与top,left,rightbottom属性设置为0:这种风格使得覆盖填充整个视口.

div覆盖里面,而不是仅仅在position: static然后就看到垂直滚动条是有关该元素.因此,内容是可滚动的,但叠加层仍然是固定的.

当您关闭缩放时,您隐藏了叠加(通过display: none),然后您也可以通过javascript(或只是内部的内容,它取决于您如何注入它)完全删除它.

作为最后一步,您还必须将noscroll类删除body(因此overflow属性返回其初始值)


Codepen示例

(它通过更改aria-hidden叠加层的属性来显示和隐藏它并增加其可访问性).

标记
(打开按钮)

<button type="button" class="open-overlay">OPEN LAYER</button>
Run Code Online (Sandbox Code Playgroud)

(叠加和关闭按钮)

<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>
Run Code Online (Sandbox Code Playgroud)

CSS

.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; }
Run Code Online (Sandbox Code Playgroud)

Javascript (vanilla-JS)

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);

});
Run Code Online (Sandbox Code Playgroud)

最后,这是另一个示例,其中叠加打开,transition应用于opacity属性的CSS具有淡入效果.还padding-right应用a以避免在滚动条消失时对基础文本进行重排.

Codepen示例(淡入淡出)

CSS

.noscroll { overflow: hidden; }

@media (min-device-width: 1025px) {
    /* not strictly necessary, just an experiment for 
       this specific example and couldn't be necessary 
       at all on some browser */
    .noscroll { 
        padding-right: 15px;
    }
}

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

[aria-hidden="true"] {    
    transition: opacity 1s, z-index 0s 1s;
    width: 100vw;
    z-index: -1; 
    opacity: 0;  
}

[aria-hidden="false"] {  
    transition: opacity 1s;
    width: 100%;
    z-index: 1;  
    opacity: 1; 
}
Run Code Online (Sandbox Code Playgroud)

  • 这是绝对正确的,但要注意,它不适用于移动游猎.背景将继续滚动,您的叠加层将被修复. (63认同)
  • 如果用户在激活叠加层时已将主体向下滚动到底部,则当您设置溢出时,这将导致主体跳到顶部:隐藏; 有什么方法吗? (20认同)
  • 它工作正常.可滚动视口容器`div`必须具有CSS样式`position:fixed`,并且具有可滚动的垂直溢出.我成功地使用了`overflow-y:auto;`和iOS动量/惯性滚动,我添加了`-webkit-overflow-scrolling:touch;`到CSS.我用`display:block;`,`width:100%;`,和`height:100%;`CSS有一个整页视口. (19认同)
  • 对不起,我不明白.将主体设置为溢出:隐藏不会禁用我的iPad iOS7上的弹性体滚动.所以我必须在我的js中添加:document.body.addEventListener('touchmove',function(event){event.preventDefault();},false); 哪个SADLY也禁止所有元素可滚动.到目前为止还没有找到任何解决方案(没有额外的插件) (9认同)
  • 这是正确的答案.有人应该给它一个复选标记,因为它是正确的. (6认同)
  • 有没有人有iOS 5 Mobile Safari的解决方案? (3认同)
  • iOS在处理视口大小方面是不正确的,它应该被完全忽略并留下它的缺点.我们无法修复非常基本概念的可怕实现. (3认同)
  • `-webkit-overflow-scrolling:touch;`在移动Safari上解决它,谢谢! (2认同)
  • 在.overlay {}你写了两次:0两次;) (2认同)
  • 很好的答案。而且它很长一段时间都是 666 票,很高兴我能把它提高到 667 以获得更好的数字(只是迷信)——谢谢你提供了一个很好的解决方案! (2认同)

am8*_*80l 71

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

body.noscroll{
    position:fixed;
    overflow:hidden;
}
Run Code Online (Sandbox Code Playgroud)

  • 使用此解决方案,由于固定位置,正文将自动滚动到您的内容的顶部.这可能会让您的用户感到不安. (96认同)
  • 使用`position:fixed`的另一个问题是它正在调整我的主体大小.也许它与其他CSS冲突,但是`overflow:hidden`就是所需要的 (3认同)
  • 当您通过输入字段选项卡时,这会突破焦点跳跃 (2认同)
  • 哈哈哈。我打开了 codepen,看到了一个 CodePen 覆盖层,要求注册一个帐户。我无法滚动背景。真是太巧合了。 (2认同)

Luc*_*cia 39

不要使用overflow: hidden;body.它会自动将所有内容滚动到顶部.也不需要JavaScript.利用overflow: auto;.此解决方案甚至适用于移动Safari:

HTML结构

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

<div class="background-content">
    lengthy content here
</div>
Run Code Online (Sandbox Code Playgroud)

造型

.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;
}
Run Code Online (Sandbox Code Playgroud)

观看演示在这里和源代码在这里.

更新:

对于想要键盘空格键,页面向上/向下工作的人:你需要专注于叠加,例如,点击它,或者在这部分div响应键盘之前手动JS聚焦它.与覆盖"关闭"时相同,因为它只是将覆盖移动到侧面.否则浏览器,这些只是两个正常的divs,它不知道为什么它应该专注于它们中的任何一个.

  • 这会以多种方式打破移动设备用户体验(即:URL-bar Hiding,Overscroll Affordance,...),甚至*空格键在桌面上滚动*. (10认同)
  • 很酷的解决方案,但后来我需要将所有内容包装在div中,我无意做... (5认同)
  • @ user18490角度/材料部分与此解决方案正常工作无关. (4认同)
  • 这是一个理想的解决方案.如果有人遇到这个问题,你可能需要添加`html,body {height:100%; }`(如在演示中),以使其正常工作. (2认同)
  • 这是更强大的选项,但它确实使事情变得复杂.例如,PageUp和PageDown不能用于刷新.任何使用`.offset()`值进行计算的东西都搞砸了...... (2认同)

Phi*_*rer 31

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

scrollPosition = window.pageYOffset;
mainEl.style.top = -scrollPosition + 'px';
Run Code Online (Sandbox Code Playgroud)

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

window.scrollTo(0, scrollPosition);
Run Code Online (Sandbox Code Playgroud)

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

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;
}
Run Code Online (Sandbox Code Playgroud)
.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;
}
Run Code Online (Sandbox Code Playgroud)
<main class="main-content"></main>

  <div class="overlay">
    <div class="overlay-content"></div>
  </div>
  
  <button class="toggle">Overlay</button>
Run Code Online (Sandbox Code Playgroud)

  • 这是唯一一个对我来说 100% 正确的解决方案,我希望我能早点找到这个答案。 (3认同)

Fra*_*dge 30

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

html, body {
    overflow: hidden;
}
Run Code Online (Sandbox Code Playgroud)

  • 这不能解决在此问题的许多其他解决方案中也看到的问题-如果在打开模式时窗口滚动到页面顶部以外的任何位置,则将导致滚动到页面顶部。我发现Philipp Mitterer的解决方案[here](/sf/answers/3166147211/)是涵盖大多数情况的最佳选择。 (2认同)

Igo*_*sow 30

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

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

.overlay {
   overscroll-behavior: contain;
   ...
}
Run Code Online (Sandbox Code Playgroud)

Codepen演示

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

有关详细信息,请查看Google开发者文章.

  • 该解决方案的问题在于它仅在叠加层可滚动时才有效。如果您有一个模态,并且所有模态都适合在屏幕上显示,那么里面没有滚动—它不会停止主体滚动。那,它也根本无法在Safari中使用:) (6认同)
  • 我一路走来告诉你这是在使用最新的Chrome,Mozilla和Opera.有一个美好的时光! (4认同)
  • 有人应该为此加上一笔赏金.这是正确的解决方案.没有必要的JavaScript.:) (3认同)

Moe*_*Moe 9

如果有人正在寻找React 函数组件的解决方案,您可以将其放入模态组件中:

 useEffect(() => {
    document.body.style.overflowY = 'hidden';
    return () =>{
      document.body.style.overflowY = 'auto';
    }
  }, [])
Run Code Online (Sandbox Code Playgroud)


NGL*_*GLN 7

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

<div id="content">
</div>
<div id="overlay">
</div>
Run Code Online (Sandbox Code Playgroud)

请参阅使用浏览器的主滚动条滚动特定DIV内容以查看其工作情况.


Wes*_*ton 7

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

  • 用手指超级"甩"仍然会<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; */
}
Run Code Online (Sandbox Code Playgroud)


黄雨伞*_*黄雨伞 6

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

overscroll-behavior: contain;
Run Code Online (Sandbox Code Playgroud)

在 CSS 中的叠加层上。


chr*_*stk 6

您可以使用一些“新”css 和 JQuery 轻松完成此操作。

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

body {
   position: static;
   overflow: auto;
}
Run Code Online (Sandbox Code Playgroud)

在“覆盖”使用时

body {
   position: sticky;
   overflow: hidden;
}
Run Code Online (Sandbox Code Playgroud)

开关的 JQuery('body'->'overlay'):

$("body").css({"position": "sticky", "overflow": "hidden"});
Run Code Online (Sandbox Code Playgroud)

用于开关的 JQuery('overlay'->'body'):

$("body").css({"position": "static", "overflow": "auto"});
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

627733 次

最近记录:

6 年,4 月 前