iOS safari 如何阻止「橡皮筋效果」?

背景:

iOS 5 之後開始支持 Native Scrolling,為 Web App 帶來媲美原生應用的滾動體驗。使用十分方便只要在 CSS 中加入:

HTML

&
&
&
& &

CSS

.wrapper {
overflow: auto;
-webkit-overflow-scrolling: touch;
}

但是 iOS Safari 在滑動的時候會有討厭的 「橡皮筋效果」 (Over Scroll):

設計:

┌─────────────┐
│ Header │
├─────────────┤
│ │
│ Scroll Area │
│ │
├─────────────┤
│ Footer │
└─────────────┘

需求:

  1. Scroll Area 支持垂直區域滾動。
  2. 滑動 Header 和 Footer 不會引發全局的 「橡皮筋效果」。
  3. Scroll Area 滑動到頂部或者底部,再向上或者向下拉動不會觸發全局的 「橡皮筋效果」。
  4. 情況2 會觸發 Scroll Area 局部的 「橡皮筋效果」。


自問自答

有一個小類庫可以阻止這個行為:joelambert/ScrollFix

但是這是一個有限的方案:[譯] ScrollFix.js:一個 iOS5 溢出滾動的(有限)修復方案 · Issue #1 · cssmagic/blog · GitHub

完美解決方案: Optimizing 「overflow:scroll」 on iOS5 [UPDATE]

HTML

&
&
&
&
& & &

添加如下樣式:

CSS

.wrapper {
overflow: auto;
-webkit-overflow-scrolling: touch;
}

.sub-wrapper {
height: 100%
overflow: auto;
}

值得注意的是 sub-wrapper 的高度必須和父容器 wrapper 的高度一致,不能包含 margin 或者 padding。這樣就可以為 wrapper 添加局部的 「橡皮筋效果」,防止觸發全局的 「橡皮筋效果」。

現在來禁用 Header 和 Footer 上效果。首先阻止全局滾動的默認行為:

function preventDefault(ev) {
ev.preventDefault()
}

document.addEventListener("touchmove", preventDefault, false)

下面判斷用戶滑動時的默認容器是否為 scroller 來操控事件冒泡,這裡把事件監聽器綁定在 document 的子元素上,這樣就可以讓我們控制是否阻止瀏覽器默認的行為:

function isScroller(el) {

// 判斷元素是否為 scroller
return el.classList.contains("scroller")
}

document.body.addEventListener("touchmove", function (ev) {
var target = ev.target

// 在 scroller 上滑動,阻止事件冒泡,啟用瀏覽器默認行為。
if (isScroller(target)) {
ev.stopPropagation()
}
}, false)

支持: iOS 5 及以上


今晚某個項目中有類似的坑。

我的業務結構如下:

&

div#topfixed

&

div#smooth_scroll

&

div#bottomfixed

疑難雜症需求:

1. 阻止smooth_scroll的[外層]進行-webkit-overflow-scrolling

2. smooth_scroll仍然保持-webkit-overflow-scrolling

坑:

在smooth_scroll的滾動區域到達頁面頂部和底部閥值的時候,再次touchmove會直接觸發原生webview的回彈效果,所以,這裡需要通過判斷手指上滑和下滑來屏蔽之。

解決方案:

function restoreEvent(ev) {
var _target = ev.target,
_ss = $(_target).parents().slice(-3)[0],
_point = ev.touches[0],
_top = _ss.scrollTop;

// 什麼時候到底部
var _bottomFaVal = _ss.scrollHeight - _ss.offsetHeight;

if(_ss.id === "smooth_scroll"){
// 到達頂端
if(_top === 0) {
// 阻止向下滑動
if(_point.clientY &> Y) {
ev.preventDefault();
} else {
// 阻止冒泡
// 正常執行
ev.stopPropagation();
}
} else if(_top === _bottomFaVal) {
// 到達底部
// 阻止向上滑動
if(_point.clientY &< Y) { ev.preventDefault(); } else { // 阻止冒泡 // 正常執行 ev.stopPropagation(); } } else if(_top &> 0 _top &< _bottomFaVal) { ev.stopPropagation(); } } }


負責的說目前沒有完美解決方案


確定這個辦法可行么,為什麼我阻止document的touchmove事件後,頁面所有的元素都不能滾動了


用css的fixed 好像可以


https://github.com/zurb/foundation-sites/issues/7548

我選擇跳轉簡單點。


踩過坑後來答一下:

cubiq/iscroll 這個庫可以完美解決問題,兼容性問題有待考證

iOS 訪問 demo: iScroll demo: scrollbars


這種方法直接導致頁面的scroll不能滾動了,這方法不行


難道說,現在可以用DIV的滾動條了?


document.getElementByTagName("body")[0].addEventListener("touchstart", function(e) {e.preventDefault();}, false)

親測可以。。。


推薦閱讀:

為什麼web前端待遇沒有iOS高?
有哪些很好的 Web App?
Web App 開發使用哪種框架比較好?
Flash網頁應用前景怎樣?
App Store上遊戲佔了16%,娛樂佔了10%,電子書(雜誌報紙)佔了16%,還有教育類應用8%,這意味著什麼?

TAG:iOS | 前端開發 | JavaScript | 網頁應用 | Safari |