首页 文章

iOS - css / js - 覆盖滚动但阻止身体滚动

提问于
浏览
13

我知道有一些类似的问题,但它们要么对我的用例不起作用,要么接受的答案有一个对我不起作用的缺陷 . 所以...

我有一个包含元素列表的页面 . 单击列表中的元素将打开一个叠加层,其中包含有关该元素的详细信息 . 我需要覆盖层可滚动但我不希望覆盖层下面的其余部分滚动,这样一旦覆盖层关闭,你就处于相同的位置(覆盖层也略微透明,因此对用户来说很烦人)看到页面在下面滚动,也是为什么我无法保存滚动并重置关闭) .

现在除了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;
}

然后在我的点击处理器中,我在 body 上切换 hidden 类,在 #overlay 上切换 open 类,并用我的内容填充 #overlay 元素 . 就像我说的那样,除了iOS之外,它在任

解决方案我见过其他地方说我需要在 body 和/或 html 标签上使用 position:fixedheight:100% . 此解决方案的问题在于您丢失了滚动位置,当您关闭叠加层时,我会选择一个选项 .

因为我需要覆盖内容可滚动,所以我无法阻止身体上的 preventDefault 完全滚动 .

还有其他建议吗?

6 回答

  • 2

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

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

    这是防止iOS滚动叠加/模态背后的内容的最佳方法 .

    然后为了保持滚动位置,我将内容向后移动,使其看起来像保留它,然后当模态关闭时恢复身体的位置 .

    我在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/

  • 2

    Why does the page scroll when I'm scrolling on the modal?

    如果您在模式后面的元素上启用了css属性 -webkit-overflow-scrolling: touch; ,则会出现一些本机代码,这似乎是在侦听我们无法捕获的touchmove事件 .

    So what now?

    我已经为我的应用程序修复了这个问题,当模态可见时,通过添加一个类来否定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>
    
  • 1

    我发现的最佳解决方案,当您使用vanilla 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 = "";
    }
    

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

    Gist

  • 6

    我们遇到了这个确切的问题 - 最后使用以下方法解决了

    https://github.com/lazd/iNoBounce

    一个问题是在脚本加载后立即调用 iNoBounce.disable() ,因为它启动时启动,从而阻止了任何滚动行为 .

  • 0

    似乎iOS只会在叠加达到最小或最大滚动时滚动主体 . 因此,将overlay的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中运行时附加活动 .

  • 13

    我在寻找解决我非常相似问题的方法时发现了这个问题 . 也许我找到的解决方案在这里会有所启发 .

    在我的例子中,问题是如何在该容器中使用可滚动小部件时阻止可滚动容器滚动(例如,使用css转换垂直旋转的HTML5滑块) . 可滚动容器使用CSS中的id选择器定义为'overflow-y:scroll' .

    我首先尝试使用具有'overflow-y:hidden'的.scroll-lock类,然后在所有可滚动小部件上使用touchstart和touchend事件侦听器在可滚动容器上打开/关闭它 . 它没用 . 尝试使用小部件导致容器滚动 . 然后我尝试了各种各样的javascript解决方案,直到我找到了这些,然后更接近解决它 .

    就我而言,问题是特异性规则 . 类选择器被id选择器打败,所以我切换了类无法覆盖由id应用的容器上的默认溢出设置 . 当我直接在容器div上使用style属性应用'overflow:hidden'时,一切正常 .

    const $scrollableWidget = $('.vertical-slider-container');
    $scrollableWidget.on('touchstart',function (e) {
        console.log("Disabling scroll on content area");
        $(`#content`).css("overflow-y", "hidden");
    });
    $scrollableWidget.on('touchend',function (e) {
        console.log("Re-enabling scroll on content area");
        $(`#content`).removeAttr("style");
    });
    

    有关详细信息,请参阅此小提琴 . (使用移动浏览器进行试用 . )

    https://jsfiddle.net/daffinm/fwgnm7hs/12/

    希望这有助于某人 . (我花了太长时间解决这个问题 . )

相关问题