如何在 iOS 13+ Safari 中禁用正文滚动(当保存为 PWA 到主屏幕时)? [重复]

问题描述 投票:0回答:9

问题:

我希望 iOS 13 Safari 上的 body 元素不滚动。这意味着没有滚动,也没有弹性反弹(溢出滚动)效果。

我设置了两个相邻的元素

overflow: scroll;
,它们应该滚动,只是它们周围的主体不应该滚动。

我尝试过的所有解决方案都不适用于渐进式网络应用程序,这些应用程序的头中有以下标签并保存到主屏幕。

<meta name="apple-mobile-web-app-capable" content="yes">

我尝试过的解决方案:

  1. 设置隐藏在正文和/或 HTML 上的溢出。不适用于 iOS 13 safari:https://stackoverflow.com/a/18037511

    html {  
        position: relative;
        overflow: hidden;
        height: 100%;
    }
    
    body {
        position: relative;
        overflow: hidden;
        height: 100%;
    }
    

    在 iOS 13 Safari 中不执行任何操作,但可以在 macOS Safari 和 Firefox 中使用。

  2. 设置位置固定在机身上。对我不起作用,因为当用户滚动时,主体不会滚动,但滚动仍然会阻止我的两个内部元素在溢出反弹动画时滚动:https://stackoverflow.com/a/47874599

    body {
        position: fixed;
    }
    

    仅将正文置于页面滚动之上。滚动(溢出滚动)通过固定主体发生。

  3. 防止默认触摸移动。不起作用(是一个较旧的解决方案......):https://stackoverflow.com/a/49853392

    document.addEventListener("touchmove", function (e) {
        e.preventDefault();
    }, { passive: false });
    
    据我所知,

    什么也没做。 Safari 和 Firefox 中均不支持。

  4. 防止窗口默认滚动并将滚动位置设置回 0。由于动画有问题,不可行。

    window.addEventListener("scroll", (e) => {
        e.preventDefault();
        window.scrollTo(0, 0);
    });
    

    将滚动位置设置回 0,但溢出滚动仍然适用,最终导致错误行为。


演示它的片段:

要自行测试,请将下面的代码片段另存为 HTML 文件,并将其保存到 iPad(或 iPad 模拟器)的主屏幕上。保存到主屏幕后,正文突然变得可滚动。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <meta name="apple-mobile-web-app-capable" content="yes">
</head>
<body>
    <style>
        body, html {
            position: relative;
            overflow: hidden;
            height: 100%;
            width: 100%;
        }
        body {
            margin: 0;
            display: flex;
            flex-direction: column;
        }

        nav, footer {
            width: 100%;
            height: 5rem;
            background: blue;
            flex-shrink: 0;
        }

        main {
            display: flex;
            height: 0;
            flex-grow: 1;
            padding: 2rem;
        }

        section {
            width: 50%;
            overflow: scroll;
            display: flex;
            flex-direction: column;
            align-items: center;
        }

        div {
            flex-shrink: 0;
            width: 25%;
            height: 18rem;
            margin: 1rem;
            background: red;
        }
    </style>

    <nav></nav>

    <main>
        <section>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
        </section>
        
        <section>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
            <div></div>
        </section>
    </main>

    <footer></footer>
</body>
</html>

他们都没有以我可以接受的方式工作。我该如何执行此操作才能在 iOS 13 Mobile Safari 中正常工作(当保存为 PWA 到主屏幕时)?

javascript html css ios mobile-safari
9个回答
13
投票

我结合了问题中的尝试2和尝试4。固定主体不显示溢出滚动,滚动重置可防止后台溢出滚动的长动画。虽然很丑,但是还蛮管用的。

body {
  position: fixed;
}
window.addEventListener("scroll", (e) => {
  e.preventDefault();
  window.scrollTo(0, 0);
});

8
投票

只需在 CSS 的 body 中添加一个 touch-action:none 即可:

body{

touch-action:none;

}


7
投票
function unlockScroll () {
    const scrollY = this.body.style.top;
    document.body.style.position = '';
    document.body.style.top = '';
    document.body.style.left = '';
    document.body.style.right = '';
    window.scrollTo(0, parseInt(scrollY || '0') * -1);
};

function lockScroll () {
    document.body.style.position = 'fixed';
    document.body.style.top = `-${window.scrollY}px`;
    document.body.style.left = '0';
    document.body.style.right = '0';
};

3
投票

在我的例子中(应用程序需要拖动来排列元素)将 touch-action 设置为

none
可以防止拖动某些元素时滚动。

例如

draggableElement.css('touch-action', 'none') // disable actions
draggableElement.css('touch-action', 'auto') // restore actions

0
投票

我之前也遇到过类似的问题,到目前为止,使用以下方法效果最好:

  • 首先,通过应用

    -webkit-overflow-scrolling: touch

  • 启用内容容器上的滚动
  • 其次,应用以下规则:

/* this part makes sure there is nowhere left to scroll */

html {
    position: static;
    overflow-y: hidden;
    height: 100%;
    max-height: 100%;
}

/* all properties don't necessarily need to be applied on both elements,
this is only used to override any existing code */

body {
    overflow: hidden;
    height: 100%;
    max-height: 100%;
}

0
投票
window.addEventListener('touchend', _ => {
    window.scrollTo(0,0)
});

在用户放开身体后,这会将身体弹回 0,0,允许用户立即向下滚动,除了立即弹回之外,不会出现任何奇怪的动画。我尝试使用平滑的滚动动画,但它的动画速度并不总是足够快。这将防止 iPhone 上的身体从弹跳弹性滚动条滚动时发生屏幕锁定,并且仅在用户松开拉力时才会触发。


0
投票

对我来说有效:

import { useEffect } from "react";

export const useOverscrollHandler = () => {
  useEffect(() => {
    const onScroll = (e: any) => {
      e.preventDefault();
      window.scrollTo(0, 0);
    };

    window.addEventListener("scroll", onScroll);

    return () => window.removeEventListener("scroll", onScroll);
  }, []);
};


-1
投票

https://github.com/willmcpo/body-scroll-lock

我目前无法测试,但这似乎值得一试。


-1
投票

这对我有用https://stackoverflow.com/a/41601290/10763156

请将

-webkit-overflow-scrolling: touch;
添加到
#overlay
元素。

请在 body 标签末尾添加此 javascript 代码:


(function () {
    var _overlay = document.getElementById('overlay');
    var _clientY = null; // remember Y position on touch start

    _overlay.addEventListener('touchstart', function (event) {
        if (event.targetTouches.length === 1) {
            // detect single touch
            _clientY = event.targetTouches[0].clientY;
        }
    }, false);

    _overlay.addEventListener('touchmove', function (event) {
        if (event.targetTouches.length === 1) {
            // detect single touch
            disableRubberBand(event);
        }
    }, false);

    function disableRubberBand(event) {
        var clientY = event.targetTouches[0].clientY - _clientY;

        if (_overlay.scrollTop === 0 && clientY > 0) {
            // element is at the top of its scroll
            event.preventDefault();
        }

        if (isOverlayTotallyScrolled() && clientY < 0) {
            //element is at the top of its scroll
            event.preventDefault();
        }
    }

    function isOverlayTotallyScrolled() {
        // https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight#Problems_and_solutions
        return _overlay.scrollHeight - _overlay.scrollTop <= _overlay.clientHeight;
    }
}())


© www.soinside.com 2019 - 2024. All rights reserved.