iOS 10 Safari: Prevent scrolling behind a fixed overlay and maintain scroll position

前端 未结 10 2172
我寻月下人不归
我寻月下人不归 2020-12-12 13:51

I\'m not able to prevent the main body content from scrolling while a fixed position overlay is showing. Similar questions have been asked many times, but all of the techniq

10条回答
  •  心在旅途
    2020-12-12 14:24

    Bohdan's solution above is great. However, it doesn't catch/block the momentum -- i.e. the case when user is not at the exact top of the page, but near the top of the page (say, scrollTop being 5px) and all of a sudden the user does a sudden massive pull down! Bohand's solution catches the touchmove events, but since -webkit-overflow-scrolling is momentum based, the momentum itself can cause extra scrolling, which in my case was hiding the header and was really annoying.

    Why is it happening?

    In fact, -webkit-overflow-scrolling: touch is a double-purpose property.

    1. The good purpose is it gives the rubberband smooth scrolling effect, which is almost necessary in custom overflow:scrolling container elements on iOS devices.
    2. The unwanted purpose however is this "oversrolling". Which is kinda making sense given it's all about being smooth and not sudden stops! :)

    Momentum-blocking Solution

    The solution I came up with for myself was adapted from Bohdan's solution, but instead of blocking touchmove events, I am changing the aforementioned CSS attribute.

    Just pass the element that has overflow: scroll (and -webkit-overflow-scrolling: touch) to this function at the mount/render time.

    The return value of this function should be called at the destroy/beforeDestroy time.

    const disableOverscroll = function(el: HTMLElement) {
        function _onScroll() {
            const isOverscroll = (el.scrollTop < 0) || (el.scrollTop > el.scrollHeight - el.clientHeight);
            el.style.webkitOverflowScrolling = (isOverscroll) ? "auto" : "touch";
            //or we could have: el.style.overflow = (isOverscroll) ? "hidden" : "auto";
        }
    
        function _listen() {
            el.addEventListener("scroll", _onScroll, true);
        }
    
        function _unlisten() {
            el.removeEventListener("scroll", _onScroll);
        }
    
        _listen();
        return _unlisten();
    }
    

    Quick short solution

    Or, if you don't care about unlistening (which is not advised), a shorter answer is:

    el = document.getElementById("overlay");
    el.addEventListener("scroll", function {
        const isOverscroll = (el.scrollTop < 0) || (el.scrollTop > el.scrollHeight - el.clientHeight);
        el.style.webkitOverflowScrolling = (isOverscroll) ? "auto" : "touch";
    }, true);
    

提交回复
热议问题