我一直在寻找一种“灯箱”类型的解决方案,它允许这样做,但还没有找到(请提出建议,如果您知道的话)。
我尝试重新创建的行为就像您在单击图片时在Pinterest上看到的一样。叠加层是可滚动的(因为整个叠加层像页面顶部的页面一样向上移动),但是叠加层后面的主体是固定的。
我试图仅使用CSS(即div
在整个页面和主体上使用的覆盖层)overflow: hidden
创建此标签,但它并不能阻止div
其滚动。
如何防止正文/页面滚动但在全屏容器中继续滚动?
我一直在寻找一种“灯箱”类型的解决方案,它允许这样做,但还没有找到(请提出建议,如果您知道的话)。
我尝试重新创建的行为就像您在单击图片时在Pinterest上看到的一样。叠加层是可滚动的(因为整个叠加层像页面顶部的页面一样向上移动),但是叠加层后面的主体是固定的。
我试图仅使用CSS(即div
在整个页面和主体上使用的覆盖层)overflow: hidden
创建此标签,但它并不能阻止div
其滚动。
如何防止正文/页面滚动但在全屏容器中继续滚动?
Answers:
理论
查看pinterest网站的当前实现(将来可能会更改),当您打开叠加层时,会将一个noscroll
类应用于该body
元素并overflow: hidden
进行设置,因此该类body
不再可滚动。
叠加(上即时或已经在页面内,并通过可见创建display: block
,它使没有区别)有position : fixed
和overflow-y: scroll
,与top
,left
,right
和bottom
属性设置为0
:这种风格使得覆盖填充整个视口。
该div
覆盖里面,而不是仅仅在position: static
然后就看到垂直滚动条是有关该元素。结果,内容是可滚动的,但是覆盖保持固定。
关闭缩放时,您可以隐藏叠加层(通过display: none
),然后也可以通过javascript将其完全删除(或仅删除其中的内容,具体取决于注入方式)。
作为最后一步,您还必须将noscroll
类删除到body
(这样,溢出属性将返回其初始值)
码
(它通过更改aria-hidden
叠加层的属性来显示和隐藏它并增加其可访问性而起作用)。
标记
(打开按钮)
<button type="button" class="open-overlay">OPEN LAYER</button>
(叠加和关闭按钮)
<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);
});
最后,这是另一个示例,其中,通过将CSS transition
应用于opacity
属性,叠加层以淡入效果打开。padding-right
当滚动条消失时,还应用a来避免基础文本上的重排。
的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;
}
div
必须具有CSS样式position:fixed
,并且具有垂直可滚动的溢出。我成功使用overflow-y:auto;
了iOS的动量/惯性滚动,并将其添加-webkit-overflow-scrolling:touch;
到CSS中。我使用display:block;
,width:100%;
和height:100%;
CSS来拥有整页视口。
如果要防止在iOS上过度滚动,可以将固定位置添加到.noscroll类
body.noscroll{
position:fixed;
overflow:hidden;
}
position:fixed
是它正在调整我的主体大小。也许它与其他CSS冲突,但overflow:hidden
仅此而已
不要overflow: hidden;
在上使用body
。它会自动将所有内容滚动到顶部。也不需要JavaScript。利用overflow: auto;
。此解决方案甚至适用于移动Safari:
<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;
}
更新:
对于希望使用键盘空格键的人,请向上/向下翻页才能正常工作:您需要专注于覆盖层,例如单击该覆盖层,或者手动JS对其进行聚焦,然后该部分div
才会响应键盘。与叠加层“关闭”时相同,因为它只是将叠加层移到侧面。否则,对于浏览器来说,这些只是两个普通div
的,并且不知道为什么要重点关注其中任何一个。
html, body { height: 100%; }
(如演示中所示)才能使其正常工作。
.offset()
值进行计算的任何内容都会弄乱,等等……
overscroll-behavior
css属性允许在到达内容的顶部/底部时覆盖浏览器的默认溢出滚动行为。
只需添加以下样式即可覆盖:
.overlay {
overscroll-behavior: contain;
...
}
目前可在Chrome,Firefox和IE(caniuse)中使用
有关更多详细信息,请参阅Google开发人员文章。
overflow-y: scroll
(从您的Codepen演示中)结合使用。@pokrishka提出的观点是正确的,但就我而言,这不是问题。无论如何,我想知道将来浏览器的实现是否将涵盖这一细节。我发现,在Firefox中,调整浏览器的大小以使模式不适合屏幕,然后再次调整它的大小,以便即使将其调整为完整大小后也可以使此属性正常工作(即包含滚动)-直到重新加载页面, 至少。
大多数解决方案都存在不能保持滚动位置的问题,因此我看了一下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>
一般而言,如果希望父级(在这种情况下为主体)在子级(在此情况下为叠加层)滚动时阻止其滚动,则应使子级成为父级的同级,以防止滚动事件冒泡。父母。如果父级是主体,则需要附加的包装元素:
<div id="content">
</div>
<div id="overlay">
</div>
请参阅使用浏览器的主滚动条滚动特定的DIV内容,以查看其工作原理。
选择的答案是正确的,但有一些限制:
<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; */
}
对于触摸设备,请尝试101vh
在覆盖层的包装中添加1px宽,最小高度的透明div。然后加-webkit-overflow-scrolling:touch; overflow-y: auto;
到包装器中。这会诱使移动浏览器认为覆盖层是可滚动的,从而拦截了来自人体的触摸事件。
这是示例页面。在移动浏览器中打开:http://www.originalfunction.com/overlay.html
https://gist.github.com/YarGnawh/90e0647f21b5fa78d2f678909673507f
-webkit-overflow-scrolling:touch;
为每个可滚动容器添加以拦截触摸事件。
我发现此问题试图解决我在Ipad和Iphone上的页面遇到的问题-当我将固定的div显示为带有图像的弹出窗口时,主体正在滚动。
一些答案很好,但是没有一个解决了我的问题。我发现了Christoffer Pettersson的博客文章。那里提供的解决方案帮助解决了我在iOS设备上遇到的问题,并解决了滚动背景问题。
正如建议那样,我将博客文章的要点包括在内,以防链接过时。
“为了禁止用户在“菜单打开”时滚动背景页面,可以通过应用一些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">
您可以使用一些“新” 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"});
我想添加到以前的答案中,因为我试图这样做,并且当我将主体切换到position:fixed时,某些布局中断了。为了避免这种情况,我还必须将身体的高度设置为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");
如果要在移动/触摸设备上禁用,则最直接的方法是使用 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;
。
尝试这个
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", "");
});
如果要停止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%,溢出为auto。在叠加层内部,您可以根据需要启用/禁用滚动。
希望这可以帮助!
就我而言,这些解决方案都无法在iPhone(iOS 11.0)上实现。
ios-10-safari-prevent-scrolling-a-fixed-overlay-and-maintain-scroll-position之后,适用于我所有设备的唯一有效解决方案是
使用下面的代码禁用和启用滚动条。
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();