Javascript 在不禁用滚动功能的情况下防止 iOS 弹跳

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/29894997/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 04:16:15  来源:igfitidea点击:

Prevent iOS bounce without disabling scroll ability

javascriptjqueryhtmlioscss

提问by Ali Samii

I am trying to implement a solution to prevent the iOS bounce effect in Safari for iOS when a web page content is larger than the viewport.

我正在尝试实施一种解决方案,以防止当网页内容大于视口时,iOS 版 Safari 中的 iOS 反弹效果。

The page I am working on is quite specific in it's structure, and is very similar to this page http://new.salt.ch/

我正在处理的页面的结构非常具体,与此页面非常相似http://new.salt.ch/

  • The basic structure is bootstrap-based.
  • It has a fixed navbar at the top.
  • It has a full-screen background slideshow.
  • The slideshow has an overlay that is fixed to the bottom of the viewport.
  • There is a footer element that loads off-canvas and is only visible on scrolling the content.
  • The content scrolls behind the navbar.
  • The content consistes of a title which is positioned 20px below the navbar and a series of buttons that are positioned 20px above the viewport.
  • When scrolling, the buttons and title all move up the screen to display the footer.
  • 基本结构是基于引导的。
  • 它在顶部有一个固定的导航栏。
  • 它有一个全屏背景幻灯片。
  • 幻灯片有一个固定在视口底部的覆盖层。
  • 有一个页脚元素可以在画布外加载并且仅在滚动内容时可见。
  • 内容在导航栏后面滚动。
  • 内容由位于导航栏下方 20 像素的标题和位于视口上方 20 像素的一系列按钮组成。
  • 滚动时,按钮和标题都会向上移动屏幕以显示页脚。

The problem I am having is the same as the problem on the page http://new.salt.ch/in that when you scroll up, you get a bounce effect at the bottom of the screen and which reveals the background and overlay.

我遇到的问题与页面http://new.salt.ch/上的问题相同,因为当您向上滚动时,屏幕底部会出现反弹效果,并显示背景和叠加层。

I have tried various solutions, including iNoBounce.js, Nonbounce.js and a few other suggestions I have found on SO.

我尝试了各种解决方案,包括 iNoBounce.js、Nonbounce.js 以及我在 SO 上找到的其他一些建议。

I have the same issue always...when I try to disable the bounce, all scrolling gets disabled. I am guessing this is because the content (other than the footer) is always just large enough that the scroll is not needed, and so scrolling gets disabled and the footer no longer is accessible on scroll.

我总是遇到同样的问题......当我尝试禁用反弹时,所有滚动都会被禁用。我猜这是因为内容(页脚除外)总是足够大以至于不需要滚动,因此滚动被禁用并且页脚不再可在滚动时访问。

采纳答案by James Campbell

This code should stop the bounce as it's the HTML tag that bounces

此代码应该停止反弹,因为它是反弹的 HTML 标记

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

回答by Sgnl

I went through a few answers on SO and things were looking bleak until stumbled upon this code.

我在 SO 上浏览了一些答案,直到偶然发现这段代码之前,事情看起来都很黯淡。

html {
  position: fixed;
  height: 100%;
  overflow: hidden;
}

body {
  width: 100vw;
  height: 100vh;
  overflow-y: scroll;
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
}

The style declarations for bodycan be put on any element that you want to have the ability to scroll. You can also alter overflow-xand overflow-yas needed. I personally needed it to NOT scroll to the sides so I declared it as so.

样式声明body可以放在任何您希望能够滚动的元素上。您还可以改变overflow-xoverflow-y需要。我个人需要它不要滚动到两侧,所以我声明它是这样。

update Sept 15 2017: I had to use this fix for another project and I was able to do without these declarations position: fixedand height: 100%;on the htmlselector. YMMV

更新2017年9月15日:我不得不使用此修补另一个项目,我能够没有这些声明做position: fixedheight: 100%;html选择。青年会

Update April 12 2018 (mentioned in comments): If you're using fixed elements on the page, those elements may have a visual "shakiness" when scrolling.

2018 年 4 月 12 日更新(在评论中提到):如果您在页面上使用固定元素,滚动时这些元素可能会出现视觉“抖动”。

回答by Jeremy Whitt

If I'm interpreting your question correctly, we've been having the same issue for years developing cross-platform mobile web apps, trying to get all the different proprietary scroll features to work correctly on each device: Apple iOS, Google Android, Windows Phone, laptop Chrome, laptop Safari, IE, and laptop Edge.

如果我正确地解释了您的问题,我们多年来一直在开发跨平台移动网络应用程序时遇到同样的问题,试图让所有不同的专有滚动功能在每个设备上正常工作:Apple iOS、Google Android、Windows手机、笔记本 Chrome、笔记本 Safari、IE 和笔记本 Edge。

jQuery Mobile continues to try and fix this within the confines of their framework, but it's too much whack-a-mole, with the constant updates from each device maker / OS maker.

jQuery Mobile 继续尝试在其框架范围内解决此问题,但由于每个设备制造商/操作系统制造商的不断更新,这太过分了。

Yes, we've got solutions for each individual mobile device. And we have tested, but not seriously considered developing device-selective paging frameworks for each device, requiring us to detect each device and present a slightly different framework for each. Insanely bad idea with basically maintaining at least 3 and really up to a dozen different versions of your code.

是的,我们为每个移动设备提供了解决方案。我们已经测试过,但没有认真考虑为每个设备开发设备选择性分页框架,要求我们检测每个设备并为每个设备提供一个略有不同的框架。基本上维护至少 3 个和实际上多达 12 个不同版本的代码,这是一个非常糟糕的主意。

SOLUTION: We've had the most luck by just putting your persistent header and footer on top of your page framework. Here is the general solution using in-line styles for simplicity:

解决方案:我们最幸运的是将持久的页眉和页脚放在页面框架的顶部。为简单起见,以下是使用内联样式的通用解决方案:

<html>
<head>
  <title>Fixed Header and Footer on All Mobile Web Apps</title>
  <meta name="viewport" content="user-scalable=no, initial-scale=1.0, maximum-scale=1.0" />
  <style>
    html, body { height:100%; width:100%; }
  </style>
</head>
<body>
<div style="position: fixed; height:100%; width:100%; top:0; left:0;">
  <div style="height:calc(100% - 1px); width:100%; margin-top: 60px; z-index: 1; overflow-y: scroll; -webkit-overflow-scrolling: touch;">
    [Body Content That Can Scroll if it extends beyond screen...]

  </div>
  <div style="position: absolute; top:0; left:0; width:100%; height: 60px; background:#dddddd; z-index:10;">
    [Header Content...]

  </div>
  <div style="position: absolute; bottom:0; left:0; width:100%; height: 40px; background:#cccccc; z-index:11;">
    [Footer Content...]

  </div>
</div>
</body>
</html>

So, the Body could be any jQuery Mobile set of pages. In fact, theoretically, the Body could be almost any content from any framework.

因此,Body 可以是任何 jQuery Mobile 页面集。事实上,从理论上讲,Body 几乎可以是任何框架中的任何内容。

Special note, the line with height:calc(100% - 1px); is critical to the magic.

特别注意,高度为:calc(100% - 1px); 是关键的魔法。

The seemingly infinite combinations or permutations of this issue have almost become a crusade for us over the years, trying to find the most pure, simplest, and most universally compatible solution. So after dedicating an embarrassing number of man-hours to this topic, this is not only our best solution, it's also the ONLY universally compatible approach we've found that also allows you to stick with just a singular code-base. It has been successfully tested on the latest versions of iOS, Windows Phone, Android, laptop Chrome, laptop Safari, PhoneGap, laptop Firefox, IE 9-11, and Windows Edge.

这个问题看似无限的组合或排列,几乎成了我们这些年来的讨伐,试图找到最纯粹、最简单、最通用的解决方案。因此,在为该主题投入了大量令人尴尬的工时后,这不仅是我们最好的解决方案,而且还是我们发现的唯一一种通用兼容的方法,它还能让您坚持使用单一的代码库。它已在最新版本的 iOS、Windows Phone、Android、笔记本电脑 Chrome、笔记本电脑 Safari、PhoneGap、笔记本电脑 Firefox、IE 9-11 和 Windows Edge 上成功测试。

TAGS: mobile app, web app, fixed header, fixed footer, persistent header, persistent footer, scroll issue, iOS scroll bounce, Chrome scroll bounce, Android scroll bounce, webkit scroll issue, webkit touch scrolling, iOS touch scrolling issue

标签:移动应用、网络应用、固定页眉、固定页脚、持久页眉、持久页脚、滚动问题、iOS 滚动反弹、Chrome 滚动反弹、Android 滚动反弹、webkit 滚动问题、webkit 触摸滚动、iOS 触摸滚动问题

回答by Zhong Huiwen

I used iNoBounce https://github.com/lazd/iNoBounceand it works perfectly!

我使用了 iNoBounce https://github.com/lazd/iNoBounce,它运行完美!

If you need to allow horizontal scrolling as well, there is a pull request by santi6291at https://github.com/lazd/iNoBounce/pull/36which fixes that

如果您还需要允许水平滚动,santi6291https://github.com/lazd/iNoBounce/pull/36 上有一个 pull request 来解决这个问题

回答by R OMS

None of these answers work in 2019 for iOS 13 mobile Safari.

这些答案都不适用于 2019 年的 iOS 13 移动版 Safari。

回答by Flavio F Lima

For 2019 Safari on iOS 13, I was able to use this fix:

对于 iOS 13 上的 2019 Safari,我能够使用此修复程序:

   html {
      overflow: hidden;
      height: 100%;
      position: fixed;
   }

   body {
      overflow: auto;
      height: 100%;
      position: relative;
  }

At least for me it covers most of the cases.

至少对我来说,它涵盖了大多数情况。

回答by Brian Haak

I managed to solve most problems supporting overflow: autoand overflow: scrollon mobile Safari:

我设法解决了支持overflow: autooverflow: scroll移动 Safari 的大多数问题:

  • without hanging the scroll view after touching at the beginning of list, then moving down and then up (mobile Safari runs its default bouncing behavior for the whole page in that case)
  • support for fixed header / action bar on top without ugly overlapping of it by a scrollbar
  • 在触摸列表开头后不挂起滚动视图,然后向下再向上移动(在这种情况下,移动 Safari 会为整个页面运行其默认的弹跳行为)
  • 支持顶部的固定标题/操作栏,而不会被滚动条丑陋重叠

window.addEventListener('DOMContentLoaded', function () {
                        
  var atTop = true;
  var atBottom = false;

  var body = document.getElementById('fixedBody');
  body.addEventListener('touchmove', function(event){
    event.preventDefault();
  });

  body.addEventListener('touchstart', function(event){
    event.preventDefault();
  });

  body.addEventListener('touchend', function(event){
    event.preventDefault();
  });

  var scrollingDiv = document.getElementById('scrollDiv');
  if (scrollingDiv.scrollHeight <= scrollingDiv.clientHeight) {
    atBottom = true;
  }

  scrollingDiv.addEventListener('scroll', function(event){
    
    if (event.target.scrollTop === 0) {
      atTop = true;
    } else {
      atTop = false;
    }
    
    if (event.target.scrollHeight - event.target.scrollTop === event.target.clientHeight) {
      atBottom = true;
    } else {
      atBottom = false;
    }
  });
  
  var lastY = 0;
  var topLock = false;
  var bottomLock = false;
  
  scrollingDiv.addEventListener('touchmove', function(event){
    event.stopPropagation();
    var currentY = event.touches[0].clientY;
    if (currentY > lastY) {
      // moved down
      if (atTop) {
        event.preventDefault();
        topLock = true;
      }

      if (bottomLock) {
        bottomLock = false;
        // TODO: Emulate finger remove and touch again here
      }
    } else if(currentY < lastY){
      // moved top
      if (atBottom) {
        event.preventDefault();
        bottomLock = true;
      }

      if (topLock) {
        topLock = false;
        // TODO: Emulate finger remove and touch again here
      }
    }
     
    lastY = currentY;
  });

  scrollingDiv.addEventListener('touchstart', function(event){
    lastY = event.touches[0].clientY;
    event.stopPropagation();
  });

  scrollingDiv.addEventListener('touchend', function(event){
    event.stopPropagation();
  });

});
<html>
<head>
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0"/>
</head>
<body id="fixedBody" style="overflow: hidden;">
  <div style="position: fixed; height: 64px; width:100%; top:0; left:0; background-color: green; z-index: 1;">
    Header
  </div>
  <div id="scrollDiv" style="position: absolute; width: 100%; top: 64px; bottom: 0px; overflow-y: auto; overflow-x: hidden; -webkit-overflow-scrolling: touch; background-color: white;">
    <div style="height: 150px; background-color: blue;">
      First
    </div>
    <div style="height: 150px; background-color: red;">
      Second
    </div>
    <div style="height: 150px; background-color: green;">
      Third
    </div>
    <div style="height: 150px; background-color: black;">
      Another
    </div>
  </div>
</body>
</html>

The only caveat I have is that when user touches and starts moving down and then up, nothing happens (expected: the list should scroll down). But at least the method prevents "pseudo scrolling down" and not confuses user.

我唯一需要注意的是,当用户触摸并开始向下然后向上移动时,没有任何反应(预期:列表应该向下滚动)。但至少该方法可以防止“伪向下滚动”并且不会混淆用户。

To overcome that last problem, it's necessary to emulate a touch end and then touch start event when direction changed (I've put "TODO" comments).

为了克服最后一个问题,有必要在方向改变时模拟触摸结束然后触摸开始事件(我已经添加了“TODO”注释)。

Update: it's possible to avoid using JavaScript code fix on iOS Cordova with DisallowOverscroll = trueand WKWebView.

更新:可以避免在 iOS Cordova 上使用DisallowOverscroll = true和使用 JavaScript 代码修复WKWebView