2016-06-08 40 views
9

我知道有类似这样的一些问题,但它们要么不适用于我的用例,要么接受的答案有一个不起作用的缺陷我。所以...iOS - css/js - 叠加滚动,但防止滚动

我有一个包含元素列表的页面。点击列表中的一个元素将打开一个覆盖图,其中包含有关该元素的详细信息。我需要覆盖层为可滚动的,但我不希望覆盖层下的页面的其余部分滚动,以便一旦覆盖层关闭,您处于相同的位置(覆盖层也略微透明,因此对用户来说很烦人看到下面的页面滚动,也为什么我不能保存scrollY和关闭重置)。

现在我除了iOS以外都在工作。这基本上就是我:

<html> 
    <body> 
     <ul id="list"> 
     <li>something 1</li> 
     <li>something 2</li> 
     <li>something 3</li> 
     <li>something 4</li> 
     <li>something 5</li> 
     </ul> 
     <div id="overlay"></div> 
    </body> 
</html> 

CSS:

body.hidden { 
    overflow: hidden; 
} 
#overlay { 
    opacity: 0; 
    top: -100vh; 
} 
#overlay.open { 
    opacity: 1; 
    overflow-y: scroll; 
    overflow-x: hidden; 
    top: 0; 
} 

然后在我点击投手我切换hidden类上body,在#overlayopen类,并与我的内容填充#overlay元素。就像我说过的,除iOS之外,这个功能很好。

解我所看到的其他地方说我需要在body和/或html标签使用position:fixedheight:100%。这个解决方案的问题在于你失去了滚动位置,当你关闭覆盖层时,你回到了页面顶部。其中一些列表可能非常长,所以对我来说这不是一种选择。

我不能阻止完全滚动preventDefault身体或某物,因为我需要覆盖内容可滚动。

其他建议?

+0

我很想看到一个干净的解决方案,但最近我有这个问题。我必须使用Javascript来记录当前的滚动位置,并在卸载叠加层时恢复它。可能是我们能做的所有事情,直到Safari获得其与网络其他部分的行为。 –

+0

你是说你不能“我不能保存scrollY和重置关闭”,或者你不知道如何。 – jerrylow

+0

正在说我不能这样做,因为叠加层是透明的,你可以看到它已经滚动,但是使用下面的答案抵消顶部修复。谢谢! – jcmitch

回答

12

现在没有办法解决这个问题。从iOS 9.3开始,仍然没有很好的方法来防止身体上的滚动。我目前在需要它的所有站点上实现的最好方法是锁定html和身体的高度和溢出。

html, body { 
    height: 100%; 
    overflow: hidden; 
} 

这是防止iOS上的overlay/modal背后的内容滚动的最佳方法。

然后,为了保持滚动位置,我将背后的内容向上移动,看起来像保留它,然后当模式关闭恢复身体的位置。

我这样做是锁定和jQuery的

var $docEl = $('html, body'), 
    $wrap = $('.content'), 
    $.scrollTop; 

$.lockBody = function() { 
    if(window.pageYOffset) { 
    scrollTop = window.pageYOffset; 

    $wrap.css({ 
     top: - (scrollTop) 
    }); 
    } 

    $docEl.css({ 
    height: "100%", 
    overflow: "hidden" 
    }); 
} 

$.unlockBody = function() { 
    $docEl.css({ 
    height: "", 
    overflow: "" 
    }); 

    $wrap.css({ 
    top: '' 
    }); 

    window.scrollTo(0, scrollTop); 
    window.setTimeout(function() { 
    scrollTop = null; 
    }, 0); 
} 

解锁功能,当你拼凑所有这些结合在一起,你得到http://codepen.io/jerrylow/pen/yJeyoG,如果你想在这里测试一下您的手机上只是结果:http://jerrylow.com/demo/ios-body-lock/

+0

谢谢!就像你说的那样,这不是完美的,但是这比我见过的任何东西都要好。解决一个没有完美解决方案的问题的好答案。 – jcmitch

+1

该演示在ios 10上有问题。有时你可以在主体中滚动,但不是模态。 – Spoeken

+0

刚刚在iOS 10中测试过,看起来对我来说很好... – buschschwick

2

我发现最好的解决方案,它可以防止背景滚动,同时使用香草草稿滚动到叠加层(固定元素)的顶部或底部javascript:

// "fixed-element" is the class of the overlay (fixed element) what has "position: fixed" 
// Call disableScroll() and enableScroll() to toggle 

var freeze = function(e) { 
    if (!document.getElementsByClassName("fixed-element")[0].contains(e.target)) { 
    e.preventDefault(); 
    } 
} 

var disableScroll = function() { 
    document.body.style.overflow = "hidden"; // Or toggle using class: document.body.className += "overflow-hidden-class"; 

    // Only accept touchmove from fixed-element 
    document.addEventListener('touchmove', freeze, false); 

    // Prevent background scrolling 
    document.getElementsByClassName("fixed-element")[0].addEventListener("touchmove", function(e) { 
    var top = this.scrollTop, 
     totalScroll = this.scrollHeight, 
     currentScroll = top + this.offsetHeight; 

    if (top === 0 && currentScroll === totalScroll) { 
     e.preventDefault(); 
    } else if (top === 0) { 
     this.scrollTop = 1; 
    } else if (currentScroll === totalScroll) { 
     this.scrollTop = top - 1; 
    } 
    }); 
} 

var enableScroll = function() { 
    document.removeEventListener("touchmove", freeze); 
    document.body.style.overflow = ""; 
} 

优点:
1.打开叠加层(固定元素)时不会使主体“固定”,因此页面不会滚动到顶部。
2.防止使用固定元素进行背景滚动。

Gist

5

为什么当我在滚动模态页面滚动?

如果您在模式后面的元素上启用了css属性-webkit-overflow-scrolling: touch;,那么某些本机代码踢起来似乎在侦听我们无法捕获的touchmove事件。

那么现在呢?

我已经解决了这个问题,我的应用程序通过添加一个类来取消css属性,当模态可见时。这是一个充分运作的例子。

let pageEl = document.querySelector(".page"); 
 
let modalEl = document.querySelector(".modal"); 
 

 
function openModal(e){ 
 
    e.preventDefault(); 
 
    pageEl.classList.add("page--has-modal"); 
 
    modalEl.classList.remove("hidden"); 
 
    window.addEventListener("wheel", preventScroll); 
 
    window.addEventListener("touchmove", preventScroll); 
 
} 
 
function closeModal(e){ 
 
    e.preventDefault(); 
 
    pageEl.classList.remove("page--has-modal"); 
 
    modalEl.classList.add("hidden"); 
 
    
 
    window.removeEventListener("wheel", preventScroll); 
 
    window.removeEventListener("touchmove", preventScroll); 
 
} 
 

 
window.addEventListener("click", function(){ 
 
    console.log(modalEl.scrollHeight); 
 
    console.log(modalEl.clientHeight); 
 
}); 
 

 
function preventScroll(e){ 
 
    if (!isDescendant(modalEl, e.target)){ 
 
    e.preventDefault(); 
 
    return false; 
 
    } 
 
    
 
    let modalTop = modalEl.scrollTop === 0; 
 
    let modalBottom = modalEl.scrollTop === (modalEl.scrollHeight -  modalEl.clientHeight); 
 
    
 
    if (modalTop && e.deltaY < 0){ 
 
    e.preventDefault(); 
 
    } else if (modalBottom && e.deltaY > 0){ 
 
    e.preventDefault(); 
 
    } 
 
} 
 

 
function isDescendant(parent, child) { 
 
    var node = child.parentNode; 
 
    while (node != null) { 
 
     if (node == parent) { 
 
      return true; 
 
     } 
 
     node = node.parentNode; 
 
    } 
 
    return false; 
 
}
.page { 
 
    -webkit-overflow-scrolling: touch; 
 
} 
 
.page--has-modal { 
 
    -webkit-overflow-scrolling: auto; 
 
} 
 

 
.modal { 
 
    position: absolute; 
 
    top: 50px; 
 
    left: 50px; 
 
    right: 50px; 
 
    bottom: 50px; 
 
    background: #c0c0c0; 
 
    padding: 50px; 
 
    text-align: center; 
 
    overflow: auto; 
 
    -webkit-overflow-scrolling: auto; 
 
} 
 
.hidden { 
 
    display: none; 
 
}
<div class="page"> 
 
<button onclick="openModal(event);">Open modal</button> 
 
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Integer consequat sapien a lectus gravida euismod. Sed vitae nisl non odio viverra accumsan. Curabitur nisi neque, egestas sed, vulputate sit amet, luctus vitae, dolor. Cras lacus massa, sagittis ut, volutpat consequat, interdum a, nulla. Vivamus rhoncus molestie nulla. Ut porttitor turpis sit amet turpis. Nam suscipit, justo quis ullamcorper sagittis, mauris diam dictum elit, suscipit blandit ligula ante sit amet mauris. Integer id arcu. Aenean scelerisque. Sed a purus. Pellentesque nec nisl eget metus varius tempor. Curabitur tincidunt iaculis lectus. Aliquam molestie velit id urna. Suspendisse in ante ac nunc commodo placerat.</p> 
 

 
<p>Morbi gravida posuere est. Fusce id augue. Sed facilisis, felis quis ornare consequat, neque risus faucibus dui, quis ullamcorper tellus lacus vitae felis. Phasellus ac dolor. Integer ante diam, consectetuer in, tempor vitae, volutpat in, enim. Integer diam felis, semper at, iaculis ut, suscipit quis, dolor. Vestibulum semper, velit et tincidunt vehicula, nisl risus eleifend ipsum, vel consectetuer enim dolor id magna. Praesent hendrerit urna ac lacus. Maecenas porttitor ipsum sed orci. In ac odio vel lorem tincidunt pellentesque. Nam tempor pulvinar turpis. Nunc in leo in libero ultricies interdum. Proin ut urna. Donec ultricies nunc dapibus justo. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Praesent vulputate, lectus pulvinar nonummy eleifend, sapien urna posuere metus, vel auctor risus odio eu augue. Cras vitae dolor. Phasellus dolor. Etiam enim. Donec erat felis, tincidunt quis, luctus in, faucibus at, est.</p> 
 
<div class="modal hidden"> 
 
Hi there! 
 
<button onclick="closeModal(event);">Close me</button> 
 
<p>Morbi gravida posuere est. Fusce id augue. Sed facilisis, felis quis ornare consequat, neque risus faucibus dui, quis ullamcorper tellus lacus vitae felis. Phasellus ac dolor. Integer ante diam, consectetuer in, tempor vitae, volutpat in, enim. Integer diam felis, semper at, iaculis ut, suscipit quis, dolor. Vestibulum semper, velit et tincidunt vehicula, nisl risus eleifend ipsum, vel consectetuer enim dolor id magna. Praesent hendrerit urna ac lacus. Maecenas porttitor ipsum sed orci. In ac odio vel lorem tincidunt pellentesque. Nam tempor pulvinar turpis. Nunc in leo in libero ultricies interdum. Proin ut urna. Donec ultricies nunc dapibus justo. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Praesent vulputate, lectus pulvinar nonummy eleifend, sapien urna posuere metus, vel auctor risus odio eu augue. Cras vitae dolor. Phasellus dolor. Etiam enim. Donec erat felis, tincidunt quis, luctus in, faucibus at, est.</p> 
 
</div> 
 
</div>

+0

你能否提供样本html?谢谢 – Alston

+0

会为工作片段添加一些html。 –

0

似乎一旦覆盖达到最小或最大滚动iOS版将只滚动体。因此,将覆盖的scrollTop设置为1而不是零,并检测onscroll事件(在iOS上是在滚动结束后触发的),并且如果在max(app.scrollHeight - app.scrollTop - app.clientHeight < 1)缩短一个像素。例如

var overlay = document.getElementById('overlay'); 

    function onScroll() { 
     if (overlay.scrollTop < 1) { 
      overlay.scrollTop = 1; 
     } else if (overlay.scrollHeight - overlay.scrollTop - overlay.clientHeight < 1)       { 
      overlay.scrollTop = overlay.scrollTop - 1; 
     } 
    } 


    overlay.addEventListener('scroll', onScroll); 

您可能想要添加一个检查并只附加在iOS中运行的事件。