注:如下全部例子均 只 在 iOS 的微信中測試過,但對於餓了麼APP的內置瀏覽器一樣適用(二者使用相同內核)css
工做中經常有須要顯示大量信息的狀況,列表超出一屏就涉及到滾動的問題。例如html
- var n = 1 ul while n <= 100 li= n++
在 iOS 中用微信打開,滾動很是順滑,so far so good!但某天產品需求有變,要求加一個固定在頭部的標題,因而改爲這樣:前端
- var n = 1 h1= "Momentum Scrolling on iOS" ul while n <= 100 li= n++
body, ul { margin: 0; } html, body { height: 100%; } body { display: flex; flex-direction: column; } h1 { flex-shrink: 0; } ul { flex: 1; overflow: scroll; }
直接用 flex 盒模型實現,動態適應標題的高度,很簡單不是麼。可是這時在 iOS 上打開後測試,發現有問題,下半部分區域滾動起來感受很不順滑,用老闆的話說就像「卡齒輪」ios
這時就有大牛推薦了傳說中的神器:-webkit-overflow-scrolling: touch
web
ul { flex: 1; overflow: scroll; -webkit-overflow-scrolling: touch; }
很簡單的一個屬性,順滑滾動效果就回來了!雖然不太明白是怎麼回事,解決問題就好。 可是產品經理又說了,須要在滾動時獲取滾動條的位置作些其餘操做。太簡單了,加個 scroll
事件搞定。segmentfault
document.querySelector('ul').addEventListener('scroll', function() { this.previousElementSibling.textContent = 'ScrollTop: ' + this.scrollTop; })
隨手寫好在瀏覽器中測試經過,然而在手機上測試就不太對勁:那個值是會變,然而滾動的時候不變,只有在滾動結束後變一次。瀏覽器
整個滾動過程當中 scroll 事件只在滾動結束後會被觸發一次,問題是出在這個所謂的神器 -webkit-overflow-scrolling
上面安全
一個只有 iOS 設備支持的非標準屬性。蘋果本身的解釋:指定是否在 overflow: scroll
的元素中使用「原生」的滾動方式微信
他包含兩個可選值:auto
和 touch
app
什麼是 stacking context
?這能夠說是CSS裏一個陰暗面,極其晦澀。有興趣的朋友能夠去看高人的解釋,這裏不作討論(其實筆者本身也不是很是明白:cry:),總之全部的坑都是由此而起。
下面列出我遇到過的坑:
嚴格來講,上面的 scroll 事件不觸發只是本坑的一個反作用,因此說沒必要考慮經過 touchmove
事件轉發 scroll
事件等點子,scroll
事件觸發了同樣檢測不到 scrollTop
屬性的變化(固然檢測手指的移動距離另說)。一樣,檢測滾動區域內部元素的 getBoundingClientRect
一樣無效。
例中起了一個無限的rAF循環不停地獲取 scrollTop
的值,然並卵。
這個更奇葩。例中用一個半透明的 div
蓋在了滾動區域 ul
上面(實踐中多是一個彈框的背部蒙版),甚至給 ul
本身加上了 pointer-events: none
,手指在 div
上滑動仍然會觸發 ul
的滾動。你能夠在顯示半透明蒙版時將 ul
的 -webkit-overflow-scrolling: touch
或 overflow: scroll
去掉,可是會形成屏幕明顯的閃爍。若是給 body
的 touchmove
事件 preventDefault()
能夠防止觸發滾動,可是是全部滾動區域都會失效。
Google 上一搜一片,可是筆者沒有遇到過,或許在新版本系統中已經修正,這裏不展開討論。
transition
……
WKWebView
替換 UIWebView
內核可能有些讀者已經發現,scroll
事件不能觸發的坑在 iOS Safari 和 iOS Chrome 瀏覽器中不存在,爲何呢?這裏要從 iOS 上瀏覽器的發展史提及。
因爲蘋果公司對安全性等緣由的考慮,蘋果公司靜止第三方瀏覽器在 iOS 設備上使用本身的瀏覽器的內核,換句話說,使用本身內核的瀏覽器都被禁止上架 AppStore。各大廠商無奈,因而長久以來,包括 Chrome
在內的全部第三方瀏覽器,都只是使用 iOS 系統內置的瀏覽器控件包一層外殼,這個控件就是 UIWebView
。這個 UIWebView
不只速度差,HTML5 支持率低,佔用內存高,還有各類各樣奇怪的問題。然而蘋果公司卻給本身的 Safari 瀏覽器開了後門。首先 Safari 使用的支持 JIT 編譯的 JS 引擎內核 Nitro
比 UIWebView
里老舊的解釋性 JavaScriptCore
內核速度搞數倍,而後 HTML5 支持度也比 UIWebView
高,還少了某些奇葩bug。長此以往就造成了 iOS 設備上 Safari 瀏覽器全面碾壓其餘第三方瀏覽器的現象。
在喬幫主撒手人寰不久以後,蘋果公司口氣終於鬆動,雖然沒有放開第三方瀏覽器內核的限制,但把 Safari
的瀏覽器內核提取了出來開放第三方瀏覽器使用,那就是現在的 WKWebView
(WK 即 Webkit 的縮寫)。但因爲 WKWebView
只支持 iOS8 以上系統,各大瀏覽器廠商並未馬上跟進。直到最近的 iOS9 時代,Chrome 成爲第一個吃螃蟹的 APP,使用了 WKWebView
內核。測試數據代表,使用 WKWebView
內核的 Chrome 瀏覽器在速度和 HTML5 支持率上已經與 Safari 瀏覽器不相上下。緊接着 Mozilla 公司宣佈 Firefox 登陸 iOS 平臺,使用的也是 WKWebView
內核(因而有了第一款基於 Webkit
內核的火狐瀏覽器 :)
不知蘋果作了什麼手腳,也許蘋果的開發人員認爲 WKWebView
的效能已經足以支撐在 scroll
事件中執行額外代碼而不形成 UI 卡頓,總之在 WKWebView
內核中滾動能夠正常觸發 scroll
事件,固然也能正常得到 scrollTop
的值。然而通過測試第二個問題仍然存在。
在這裏筆者強烈建議各個 APP 遷移內嵌瀏覽器至新的 WKWebView
內核。可是就我看到的,包括微信和餓了麼在內,幾乎全部的國產 APP 都還在使用 UIWebView
內核,這不得不說是一大前端開發之殤。
好比前段時間很火的 iScroll,筆者曾近也使用過一段時間。最後得出的結論是:iScroll 挖出的坑不比它填上的坑少,好比在 iScroll 里加個 click
事件都要當心翼翼、特別對待(由於絕大多數狀況綁定 touch
事件的回調函數裏第一件作的事情就是 preventDefault
)。
最值得一提的是 iScroll 的速度問題,比原生實在相差太多,在中低端安卓機型上卡頓明顯,若是還要綁定 scroll
事件作些別的事情就更卡了。
總之筆者並不建議使用。
也許這纔是真正的終極解決之道