在移动 Safari 上禁用滚动和弹跳效果

发布于 2024-12-09 14:19:14 字数 102 浏览 4 评论 0原文

我正在开发一个基于浏览器的应用程序,目前我正在为 iPad 的移动 Safari 浏览器开发和设计样式。

我正在寻找两件事:如何禁用不需要垂直滚动的页面?如何禁用弹性反弹效果?

I'm working on a browser based app, currently I'm developing and styling for the mobile Safari browser for iPad.

I'm looking for two things: How can I disable vertical scrolling for pages that don't require it? And how can I disable the elastic bounce effect?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(24

倾城花音 2024-12-16 14:19:15

这个答案不再是最先进的,除非您正在为非常旧的 iOS 设备进行开发...请参阅其他解决方案


2011 年答案:对于在 iOS Safari 中运行的 web/html 应用程序,您需要一些东西对于

document.ontouchmove = function(event){
    event.preventDefault();
}

iOS 5,您可能需要考虑以下因素: document.ontouchmove 和滚动iOS 5

2014 年 9 月更新:
更彻底的方法可以在这里找到:https://github.com/luster-io/prevent -过度滚动。有关此内容以及大量有用的 Web 应用程序建议,请参阅 http://www.luster.io/blog/9-29-14-mobile-web-checklist.html

2016 年 3 月更新:最后链接不再有效 - 请参阅https://web.archive.org/web/20151103001838/http://www.luster.io/blog/9-29-14-mobile-web-checklist.html 用于存档版本反而。感谢@falsarella 指出了这一点。

This answer is no longer state of the art, unless you are developing for a very old iOS device... Please see other solutions


2011 answer: For a web/html app running inside iOS Safari you want something like

document.ontouchmove = function(event){
    event.preventDefault();
}

For iOS 5 you may want to take the following into account: document.ontouchmove and scrolling on iOS 5

Update September 2014:
A more thorough approach can be found here: https://github.com/luster-io/prevent-overscroll. For that and a whole lot of useful webapp advice, see http://www.luster.io/blog/9-29-14-mobile-web-checklist.html

Update March 2016: That last link is no longer active - see https://web.archive.org/web/20151103001838/http://www.luster.io/blog/9-29-14-mobile-web-checklist.html for the archived version instead. Thanks @falsarella for pointing that out.

软糖 2024-12-16 14:19:15

您还可以将 body/html 的位置更改为固定:

body,
html {
  position: fixed;
}

You can also change the position of the body/html to fixed:

body,
html {
  position: fixed;
}
永言不败 2024-12-16 14:19:15

为了防止在现代移动浏览器上滚动,您需要添加被动:false。在找到这个解决方案之前,我一直在费尽心思让它发挥作用。我只在互联网上的另一处发现了这一点。

function preventDefault(e){
    e.preventDefault();
}

function disableScroll(){
    document.body.addEventListener('touchmove', preventDefault, { passive: false });
}
function enableScroll(){
    document.body.removeEventListener('touchmove', preventDefault);
}

To prevent scrolling on modern mobile browsers you need to add the passive: false. I had been pulling my hair out getting this to work until I found this solution. I have only found this mentioned in one other place on the internet.

function preventDefault(e){
    e.preventDefault();
}

function disableScroll(){
    document.body.addEventListener('touchmove', preventDefault, { passive: false });
}
function enableScroll(){
    document.body.removeEventListener('touchmove', preventDefault);
}

不知在何时 2024-12-16 14:19:15

iOS 16 现在支持 css overscroll-behavior。 iOS 16 设备,为了防止弹性反弹效果,请将以下 CSS 添加到 html 根

html {
  overscroll-behavior: none;
}

请注意,提供的解决方案仅在内容大于视口时禁用弹性反弹效果。

如果您还想完全禁用 iOS 设备上主页的滚动,请使用

html body {
   overflow: hidden;
}

css overscroll-behavior is now supported in iOS 16. If you are targeting > iOS 16 devices, to prevent elastic bounce effect, add the following CSS to the html root

html {
  overscroll-behavior: none;
}

Please note, the solution provided only disables elastic bounce effect when content is larger than viewport.

If you also want to completely disable scrolling in main page on iOS devices, use

html body {
   overflow: hidden;
}
維他命╮ 2024-12-16 14:19:15

您可以使用此 jQuery 代码片段来执行此操作:

$(document).bind(
      'touchmove',
          function(e) {
            e.preventDefault();
          }
);

这将阻止垂直滚动以及页面上发生的任何反弹效果。

You can use this jQuery code snippet to do this:

$(document).bind(
      'touchmove',
          function(e) {
            e.preventDefault();
          }
);

This will block the vertical scrolling and also any bounce back effect occurring on your pages.

深者入戏 2024-12-16 14:19:15
overflow: scroll;
-webkit-overflow-scrolling: touch;

在容器上,您可以在元素内部设置反弹效果

源:http://www.kylejlarson.com/blog/2011/fixed-elements-and-scrolling-divs-in-ios-5/

overflow: scroll;
-webkit-overflow-scrolling: touch;

On container you can set bounce effect inside element

Source: http://www.kylejlarson.com/blog/2011/fixed-elements-and-scrolling-divs-in-ios-5/

千紇 2024-12-16 14:19:15

我知道这有点偏离滑雪道,但我一直在使用 Swiffy 将 Flash 转换为交互式 HTML5 游戏,并遇到了相同的滚动问题,但没有找到有效的解决方案。

我遇到的问题是 Swiffy 阶段占据了整个屏幕,因此一旦加载,文档 touchmove 事件就永远不会被触发。

如果我尝试将相同的事件添加到 Swiffy 容器中,它会在舞台加载后立即被替换。

最后,我通过将 touchmove 事件应用于舞台内的每个 DIV 来解决它(相当混乱)。由于这些 div 也在不断变化,我需要不断检查它们。

这是我的解决方案,看起来效果很好。我希望这对尝试找到与我相同的解决方案的其他人有所帮助。

var divInterval = setInterval(updateDivs,50);
function updateDivs(){
$("#swiffycontainer > div").bind(
    'touchmove',
     function(e) {
        e.preventDefault();
    }
);}

I know this is slightly off-piste but I've been using Swiffy to convert Flash into an interactive HTML5 game and came across the same scrolling issue but found no solutions that worked.

The problem I had was that the Swiffy stage was taking up the whole screen, so as soon as it had loaded, the document touchmove event was never triggered.

If I tried to add the same event to the Swiffy container, it was replaced as soon as the stage had loaded.

In the end I solved it (rather messily) by applying the touchmove event to every DIV within the stage. As these divs were also ever-changing, I needed to keep checking them.

This was my solution, which seems to work well. I hope it's helpful for anyone else trying to find the same solution as me.

var divInterval = setInterval(updateDivs,50);
function updateDivs(){
$("#swiffycontainer > div").bind(
    'touchmove',
     function(e) {
        e.preventDefault();
    }
);}
夏至、离别 2024-12-16 14:19:15

删除ipad safari的代码:禁用滚动和弹跳效果

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

如果文档中有canvas标签,有时会影响Canvas内对象的可用性(例如:对象的移动);所以添加下面的代码来修复它。

    document.getElementById("canvasId").addEventListener("touchmove", function (e) {
        e.stopPropagation();
    }, { passive: false });

Code to To remove ipad safari: disable scrolling, and bounce effect

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

If you have canvas tag inside document, sometime it will affect the usability of object inside Canvas(example: movement of object); so add below code to fix it.

    document.getElementById("canvasId").addEventListener("touchmove", function (e) {
        e.stopPropagation();
    }, { passive: false });
原来是傀儡 2024-12-16 14:19:15

这些解决方案都不适合我。我就是这样做的。

  html,body {
      position: fixed;
      overflow: hidden;
    }
  .the_element_that_you_want_to_have_scrolling{
      -webkit-overflow-scrolling: touch;
  }

none of the solutions works for me. This is how I do it.

  html,body {
      position: fixed;
      overflow: hidden;
    }
  .the_element_that_you_want_to_have_scrolling{
      -webkit-overflow-scrolling: touch;
  }
魂归处 2024-12-16 14:19:15

尝试这个 JS 解决方案:

var xStart, yStart = 0; 

document.addEventListener('touchstart', function(e) {
    xStart = e.touches[0].screenX;
    yStart = e.touches[0].screenY;
}); 

document.addEventListener('touchmove', function(e) {
    var xMovement = Math.abs(e.touches[0].screenX - xStart);
    var yMovement = Math.abs(e.touches[0].screenY - yStart);
    if((yMovement * 3) > xMovement) {
        e.preventDefault();
    }
});

防止默认的 Safari 滚动和弹跳手势,而不分离触摸事件侦听器。

Try this JS sollutuion:

var xStart, yStart = 0; 

document.addEventListener('touchstart', function(e) {
    xStart = e.touches[0].screenX;
    yStart = e.touches[0].screenY;
}); 

document.addEventListener('touchmove', function(e) {
    var xMovement = Math.abs(e.touches[0].screenX - xStart);
    var yMovement = Math.abs(e.touches[0].screenY - yStart);
    if((yMovement * 3) > xMovement) {
        e.preventDefault();
    }
});

Prevents default Safari scrolling and bounce gestures without detaching your touch event listeners.

财迷小姐 2024-12-16 14:19:15

改进的答案@Ben Bos和@Tim评论

此CSS将有助于防止CSS重新渲染的滚动和性能问题,因为位置改变/没有宽度和高度的小滞后

html,
body {
  position: fixed;
  width: 100%; 
  height: 100%
}

improved answer @Ben Bos and commented by @Tim

This css will help prevent scrolling and performance issue with css re-render because position changed / little lagging without width and height

html,
body {
  position: fixed;
  width: 100%; 
  height: 100%
}

秋心╮凉 2024-12-16 14:19:15

这个 CSS 解决方案对我有用(仅限 iOS,我发现它最烦人):

@supports (-webkit-touch-callout: none) {
    html {
        overscroll-behavior-y: none;
    }
}

This CSS solution worked for me (iOS-only, where I found it most annoying):

@supports (-webkit-touch-callout: none) {
    html {
        overscroll-behavior-y: none;
    }
}
椵侞 2024-12-16 14:19:15

对于那些使用 MyScript Web 应用程序并且正在努力解决正文滚动/拖动问题(在 iPad 和平板电脑上)而不是实际编写的人:

已修复对我来说。

For those who are using MyScript the Web App and are struggling with the body scrolling/dragging (on iPad and Tablets) instead of actually writing:

<body touch-action="none" unresolved>

That fixed it for me.

狼性发作 2024-12-16 14:19:15

在 iPhone 上测试。只需在目标元素容器上使用此 css,它就会改变滚动行为,当手指离开屏幕时滚动行为会停止。

-webkit-overflow-scrolling: auto

https://developer.mozilla.org/en -US/docs/Web/CSS/-webkit-overflow-scrolling

Tested in iphone. Just use this css on target element container and it will change the scrolling behaviour, which stops when finger leaves the screen.

-webkit-overflow-scrolling: auto

https://developer.mozilla.org/en-US/docs/Web/CSS/-webkit-overflow-scrolling

极度宠爱 2024-12-16 14:19:15

您可以使用 js 来防止滚动:

let body = document.body;

let hideScroll = function(e) {
  e.preventDefault();
};

function toggleScroll (bool) {

  if (bool === true) {
    body.addEventListener("touchmove", hideScroll);
  } else {
    body.removeEventListener("touchmove", hideScroll);
  }
}

而不仅仅是在打开/关闭模式时运行/停止 toggleScroll 函数。

像这样 toggleScroll(true) /toggleScroll(false)

(这仅适用于 iOS,在 Android 上不起作用)

You can use js for prevent scroll:

let body = document.body;

let hideScroll = function(e) {
  e.preventDefault();
};

function toggleScroll (bool) {

  if (bool === true) {
    body.addEventListener("touchmove", hideScroll);
  } else {
    body.removeEventListener("touchmove", hideScroll);
  }
}

And than just run/stop toggleScroll func when you opnen/close modal.

Like this toggleScroll(true) / toggleScroll(false)

(This is only for iOS, on Android not working)

梦行七里 2024-12-16 14:19:15

尝试这个切换 webkitOverflowScrolling 样式的 JS 解决方案。这里的技巧是,这种风格关闭后,移动版 Safari 会转为普通滚动并防止过度弹跳——可惜的是,它无法取消正在进行的拖动。这个复杂的解决方案还跟踪 onscroll,因为顶部的弹跳会使 scrollTop 为可跟踪的负值。该解决方案在 iOS 12.1.1 上进行了测试,有一个缺点:在加速滚动时,由于重置样式可能不会立即取消它,仍然会发生单次过度弹跳。

function preventScrollVerticalBounceEffect(container) {
  setTouchScroll(true) //!: enable before the first scroll attempt

  container.addEventListener("touchstart", onTouchStart)
  container.addEventListener("touchmove", onTouch, { passive: false })
  container.addEventListener("touchend", onTouchEnd)
  container.addEventListener("scroll", onScroll)

  function isTouchScroll() {
    return !!container.style.webkitOverflowScrolling
  }

  let prevScrollTop = 0, prevTouchY, opid = 0

  function setTouchScroll(on) {
    container.style.webkitOverflowScrolling = on ? "touch" : null

    //Hint: auto-enabling after a small pause makes the start
    // smoothly accelerated as required. After the pause the
    // scroll position is settled, and there is no delta to
    // make over-bounce by dragging the finger. But still,
    // accelerated content makes short single over-bounce
    // as acceleration may not be off instantly.

    const xopid = ++opid
    !on && setTimeout(() => (xopid === opid) && setTouchScroll(true), 250)

    if(!on && container.scrollTop < 16)
      container.scrollTop = 0
    prevScrollTop = container.scrollTop
  }

  function isBounceOverTop() {
    const dY = container.scrollTop - prevScrollTop
    return dY < 0 && container.scrollTop < 16
  }

  function isBounceOverBottom(touchY) {
    const dY = touchY - prevTouchY

    //Hint: trying to bounce over the bottom, the finger moves
    // up the screen, thus Y becomes smaller. We prevent this.

    return dY < 0 && container.scrollHeight - 16 <=
      container.scrollTop + container.offsetHeight
  }

  function onTouchStart(e) {
    prevTouchY = e.touches[0].pageY
  }

  function onTouch(e) {
    const touchY = e.touches[0].pageY

    if(isBounceOverBottom(touchY)) {
      if(isTouchScroll())
        setTouchScroll(false)
      e.preventDefault()
    }

    prevTouchY = touchY
  }

  function onTouchEnd() {
    prevTouchY = undefined
  }

  function onScroll() {
    if(isTouchScroll() && isBounceOverTop()) {
      setTouchScroll(false)
    }
  }
}

Try this JS solution that toggles webkitOverflowScrolling style. The trick here is that this style is off, mobile Safari goes to ordinary scrolling and prevents over-bounce — alas, it is not able to cancel ongoing drag. This complex solution also tracks onscroll as bounce over the top makes scrollTop negative that may be tracked. This solution was tested on iOS 12.1.1 and has single drawback: while accelerating the scroll single over-bounce still happens as resetting the style may not cancel it immediately.

function preventScrollVerticalBounceEffect(container) {
  setTouchScroll(true) //!: enable before the first scroll attempt

  container.addEventListener("touchstart", onTouchStart)
  container.addEventListener("touchmove", onTouch, { passive: false })
  container.addEventListener("touchend", onTouchEnd)
  container.addEventListener("scroll", onScroll)

  function isTouchScroll() {
    return !!container.style.webkitOverflowScrolling
  }

  let prevScrollTop = 0, prevTouchY, opid = 0

  function setTouchScroll(on) {
    container.style.webkitOverflowScrolling = on ? "touch" : null

    //Hint: auto-enabling after a small pause makes the start
    // smoothly accelerated as required. After the pause the
    // scroll position is settled, and there is no delta to
    // make over-bounce by dragging the finger. But still,
    // accelerated content makes short single over-bounce
    // as acceleration may not be off instantly.

    const xopid = ++opid
    !on && setTimeout(() => (xopid === opid) && setTouchScroll(true), 250)

    if(!on && container.scrollTop < 16)
      container.scrollTop = 0
    prevScrollTop = container.scrollTop
  }

  function isBounceOverTop() {
    const dY = container.scrollTop - prevScrollTop
    return dY < 0 && container.scrollTop < 16
  }

  function isBounceOverBottom(touchY) {
    const dY = touchY - prevTouchY

    //Hint: trying to bounce over the bottom, the finger moves
    // up the screen, thus Y becomes smaller. We prevent this.

    return dY < 0 && container.scrollHeight - 16 <=
      container.scrollTop + container.offsetHeight
  }

  function onTouchStart(e) {
    prevTouchY = e.touches[0].pageY
  }

  function onTouch(e) {
    const touchY = e.touches[0].pageY

    if(isBounceOverBottom(touchY)) {
      if(isTouchScroll())
        setTouchScroll(false)
      e.preventDefault()
    }

    prevTouchY = touchY
  }

  function onTouchEnd() {
    prevTouchY = undefined
  }

  function onScroll() {
    if(isTouchScroll() && isBounceOverTop()) {
      setTouchScroll(false)
    }
  }
}
半仙 2024-12-16 14:19:15

考虑以下架构:

<body> <div id="root"></div> </body>

这个 css 可以工作:

#root { position: fixed; height: 100%; overflow: auto; }

Consider the following architecture:

<body> <div id="root"></div> </body>

this css will work:

#root { position: fixed; height: 100%; overflow: auto; }
三生路 2024-12-16 14:19:15
body {
   touch-action:none;
}

使用 JQuery

// Disable
$("body").css({ "touch-action": "none" })

// Enable
$("body").css({ "touch-action": "auto" })
body {
   touch-action:none;
}

Using JQuery

// Disable
$("body").css({ "touch-action": "none" })

// Enable
$("body").css({ "touch-action": "auto" })
夏の忆 2024-12-16 14:19:15

对于那些不想摆脱弹跳而只是想知道弹跳何时停止的人(例如开始计算屏幕距离),您可以执行以下操作(容器是溢出的容器元素):

    const isBouncing = this.container.scrollTop < 0 ||
    this.container.scrollTop + this.container.offsetHeight >
        this.container.scrollHeight

For those of you who don't want to get rid of the bouncing but just to know when it stops (for example to start some calculation of screen distances), you can do the following (container is the overflowing container element):

    const isBouncing = this.container.scrollTop < 0 ||
    this.container.scrollTop + this.container.offsetHeight >
        this.container.scrollHeight
眸中客 2024-12-16 14:19:15

禁用 safari 弹跳滚动效果:

html,
body {
  height: 100%;
  width: 100%;
  overflow: auto;
  position: fixed;
}  

Disable safari bounce scrolling effect:

html,
body {
  height: 100%;
  width: 100%;
  overflow: auto;
  position: fixed;
}  
彻夜缠绵 2024-12-16 14:19:15

当带有滚动的菜单打开并且位于滚动高度的顶部或底部时,我在抓取后台的 html 元素时遇到了问题。我尝试了很多事情。将 html 位置设置为 fixed 是我最接近锁定屏幕的方法,但在 PWA 中,它导致底部出现白色区域,我无法修复。
最后我找到了一个对我有用的解决方案

I had an issue with grabbing the html element in the background, when a menu with scroll was open and either at the top or at the bottom at the scroll height. I tried lots of things. Setting html position to fixed was the closest I got to lock the screen, but in the PWA it resulted in a white area at the bottom, that I couldn't fix.
Finally I've found a solution, that worked for me ????:

html {
    width: 100%;
    height: 100%;
    overflow: hidden;
}

body {
    margin: 0;
    height: calc(100vh - 1px)
    overflow: hidden;
    background-color: 'Whatever color you need to hide the 1px at the bottom'
}

Because it only seems to be an issue on iOS, I have targeted the devices from iPhone X to 12 Pro Max:

body {
    margin: 0;
    overflow: hidden;
    background-color: '#TIP: You can use the color picker from the inspector';

    @media only screen and (min-width: 375px) and (max-height: 926px) and (-webkit-device-pixel-ratio: 3) {
        height: calc(100vh - 1px);
    }
}

This is preventing any kind of scroll, touch or grab in the html or body elements, and scroll is still working in the menu or where else specified. Cheers.

夜空下最亮的亮点 2024-12-16 14:19:15

这就是我解决它的方法:


let touchMoveBool = false;
function handleTouchMoveEvent(e) {
    if (touchMoveBool) {
        console.log('preventing touchmove');
        e.preventDefault(); // prevent the default scrolling behaviour including pull down to refresh
    } else {
        console.log('NOT preventing touchmove');
    }
}
    
// Grab the html for an iOS device else grab the body of an android.
if (navigator.platform.match(/iPad|iPhone|iPod/)) {
    document.documentElement.addEventListener('touchmove', handleTouchMoveEvent, { passive: false });
} else {
    document.body.addEventListener('touchmove', handleTouchMoveEvent, { passive: false });
}

然后你只需在你想要/不想要能够滚动或具有滚动行为的代码部分中切换布尔值

This is how I solved it:


let touchMoveBool = false;
function handleTouchMoveEvent(e) {
    if (touchMoveBool) {
        console.log('preventing touchmove');
        e.preventDefault(); // prevent the default scrolling behaviour including pull down to refresh
    } else {
        console.log('NOT preventing touchmove');
    }
}
    
// Grab the html for an iOS device else grab the body of an android.
if (navigator.platform.match(/iPad|iPhone|iPod/)) {
    document.documentElement.addEventListener('touchmove', handleTouchMoveEvent, { passive: false });
} else {
    document.body.addEventListener('touchmove', handleTouchMoveEvent, { passive: false });
}

Then you just have to toggle the boolean in the section of code that you want/don't-want to be able to scroll or have the scroll behaviour

谈下烟灰 2024-12-16 14:19:15

与愤怒的猕猴桃类似,我使用高度而不是位置来让它工作:

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

.the_element_that_you_want_to_have_scrolling{
  -webkit-overflow-scrolling: touch;
}

Similar to angry kiwi I got it to work using height rather than position:

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

.the_element_that_you_want_to_have_scrolling{
  -webkit-overflow-scrolling: touch;
}
知足的幸福 2024-12-16 14:19:15

解决方案经过测试,适用于 iOS 12.x

这是我遇到的问题:

<body> <!-- the whole body can be scroll vertically -->
  <article>

    <my_gallery> <!-- some picture gallery, can be scroll horizontally -->
    </my_gallery>

  </article>
</body>

当我滚动图库时,主体总是自行滚动(人类滑动并不是真正水平的),这使得我的图库毫无用处。

这是我在画廊开始滚动时所做的事情

var html=jQuery('html');
html.css('overflow-y', 'hidden');
//above code works on mobile Chrome/Edge/Firefox
document.ontouchmove=function(e){e.preventDefault();} //Add this only for mobile Safari

以及当我的画廊结束滚动时所做的事情...

var html=jQuery('html');
html.css('overflow-y', 'scroll');
document.ontouchmove=function(e){return true;}

希望这会有所帮助〜

Solution tested, works on iOS 12.x

This is problem I was encountering :

<body> <!-- the whole body can be scroll vertically -->
  <article>

    <my_gallery> <!-- some picture gallery, can be scroll horizontally -->
    </my_gallery>

  </article>
</body>

While I scrolling my gallery, the body always scrolling itself (human swipe aren't really horizontal), that makes my gallery useless.

Here's what I did while my gallery start scrolling

var html=jQuery('html');
html.css('overflow-y', 'hidden');
//above code works on mobile Chrome/Edge/Firefox
document.ontouchmove=function(e){e.preventDefault();} //Add this only for mobile Safari

And when my gallery end its scrolling...

var html=jQuery('html');
html.css('overflow-y', 'scroll');
document.ontouchmove=function(e){return true;}

Hope this helps~

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文