防止滚动,但允许覆盖滚动
我一直在寻找一个“灯箱”types的解决scheme,允许这个,但还没有find一个(请,build议如果你知道任何)。
我试图重新创build的行为就像点击图片时在Pinterest上看到的一样。 覆盖层是可滚动的( 因为整个覆盖层像页面顶部一样向上移动 ),但覆盖层后面的主体是固定的。
我试图用CSS创build它(例如,在整个页面顶部的div覆盖和具有overflow: hidden主体 ),但是它不阻止div被滚动。 
如何保持身体/页面滚动,但保持在全屏容器内滚动?
理论
 查看当前pinterest站点的实现(它可能在将来会改变),当你打开覆盖时, noscroll类被应用到body元素并且overflow: hidden被设置,因此body不再是可滚动的。 
 覆盖(即时创build或已经在页面内部,通过display: block ,没有区别) position : fixed和overflow-y: scroll , top , left , right和bottom属性设置为0 :这种风格使覆盖填充整个视口。 
 叠加层中的div只是position: static那么您看到的垂直滚动条与该元素有关。 因此内容是可滚动的,但覆盖保持不变。 
 当你closures缩放,你可以隐藏覆盖(通过display: none ),然后你也可以完全通过JavaScript(或只是内部的内容,它取决于你如何注入它)删除它。 
 作为最后一步,你还必须删除noscroll类的body (所以溢出属性返回到它的初始值) 
码
Codepen示例
  (它通过改变叠加层的aria-hidden属性来工作,以显示和隐藏它并增加其可访问性)。 
  标记 
  (打开button) 
 <button type="button" class="open-overlay">OPEN LAYER</button> 
(覆盖和closuresbutton)
 <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> 
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; } 
Javascript (香草-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); }); 
 最后,这里是另一个示例,其中叠加层通过应用于opacity属性的CSS transition以淡入效果打开。 另外,当滚动条消失时,应用padding-right可以避免底层文本重排。 
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; top: 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; } 
如果你想防止在ios上过度滚动,你可以添加固定到你的.noscroll类的位置
 body.noscroll{ position:fixed; overflow:hidden; } 
值得注意的是,有时在车身标签中join“overflow:hidden”并不能完成这项工作。 在这些情况下,您也必须将该属性添加到html标记中。
 html, body { overflow: hidden; } 
 不要使用overflow: hidden; 在body 。 它会自动将所有内容滚动到顶部。 也不需要JavaScript。 利用overflow: auto;  。 该解决scheme甚至适用于移动Safari: 
HTML结构
 <div class="overlay"> <div class="overlay-content"></div> </div> <div class="background-content"> lengthy content here </div> 
造型
 .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; } 
在这里看到演示和源代码。
 大多数解决scheme都有问题,他们不保留滚动的位置,所以我看看Facebook如何做。 除了将下层内容设置为position: fixed之外,他们还会dynamic设置顶部以保留滚动位置: 
 scrollPosition = window.pageYOffset; mainEl.style.top = -scrollPosition + 'px'; 
然后,当您再次移除叠加层时,您需要重置滚动位置:
 window.scrollTo(0, scrollPosition); 
我创build了一个小例子来演示这个解决scheme
 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; } 
  <main class="main-content"></main> <div class="overlay"> <div class="overlay-content"></div> </div> <button class="toggle">Overlay</button> 
一般来说,如果你想要一个父(在这种情况下)的身体来防止它滚动,当一个孩子(在这种情况下,覆盖)滚动,然后使该孩子的父母的兄弟,以防止滚动事件冒泡父母。 如果父母是身体,则需要额外的包装元素:
 <div id="content"> </div> <div id="overlay"> </div> 
请参阅使用浏览器的主滚动条滚动特定的DIV内容以查看其工作。
我发现这个问题试图解决我的问题,我的页面上Ipad和Iphone – 身体正在滚动,当我显示固定的div作为与图像popup。
有些答案是好的,但是没有一个解决了我的问题。 我find了Christoffer Pettersson的博客文章。 在那里提出的解决scheme,帮助我的iOS设备的问题,它帮助我的滚动背景问题。
我学习iOS Safari的橡皮筋滚动的六件事
正如有人build议我包括博客文章的主要观点,以防链接过期。
“为了禁用用户可以在”菜单打开“时滚动背景页面,通过应用一些JavaScript和CSS类,可以控制哪些元素应该被允许滚动或者不滚动。
基于这个Stackoverflow的答案,你可以控制禁用滚动的元素,当touchmove事件被触发时,不应该执行默认的滚动操作。
  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"> 
 对于触摸设备,请尝试在覆盖层的包装中添加1px宽, 101vh最小高度的透明div。 然后添加-webkit-overflow-scrolling:touch; overflow-y: auto; -webkit-overflow-scrolling:touch; overflow-y: auto; 包装。 这诱使移动Safari浏览器认为覆盖是可滚动的,从而拦截触摸事件从身体。 
这是一个示例页面。 在移动Safari上打开: http : //www.originalfunction.com/overlay.html
https://gist.github.com/YarGnawh/90e0647f21b5fa78d2f678909673507f
我想添加到以前的答案,因为我试图做到这一点,一旦我切换到正确的位置,一些布局中断:固定。 为了避免这一点,我还必须将身体的高度设置为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"); } 
使用下面的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"); 
所选的答案是正确的,但有一些限制:
-  用手指超级硬“fl”仍然会在背景中滚动<body>
-  通过敲击模式中的<input>来打开虚拟键盘,将把所有将来的卷轴指向<body>
对于第一个问题,我没有解决的办法,但是想澄清第二个问题。 令人困惑的是,Bootstrap用来logging键盘问题,但他们声称已经修复了,引用http://output.jsbin.com/cacido/quiet作为修复的例子。;
事实上,这个例子在我的testing中正常工作。 但是,将其升级到最新的Bootstrap(v4)将会破坏它。
为了弄清楚它们之间的区别,我减less了一个testing用例,不再依赖于Bootstrap, http://codepen.io/WestonThayer/pen/bgZxBG 。
 决定因素是奇怪的。 避免键盘问题似乎要求在包含模态的根<div>上不设置background-color ,并且模式的内容必须嵌套在可以设置background-color另一个<div> 。 
要testing它,请在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; */ } 
 如果意图是禁用移动/触摸设备,那么最直接的方法是使用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> 
使用下面的代码来禁用和启用滚动条。
 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();