今天做項目的時候,做了個顯示活動詳情的浮層,因為內容比較多所以浮層內需要滾動,然后就引發(fā)了一系列的問題
滾動冒泡,導致浮層下的內容頁會滾動
這是個亙古不變的問題了,一個項目不遇到的都不舒服,網上探討這個問題的也非常之多,但經過我多番嘗試,都沒能完美的解決,其中安卓和 iOS 端的差異最為煩人,話不多說直接解決問題。
固定body
既然沒有辦法很好的解決冒泡,那就直接斬草除根,從最根源的地方控制它,讓他滾不起來。給 body 添加樣式(以下討論都是基于浮層已經出現(xiàn)的情況):
body.frozen {
position: fixed;
top: 0;
left: 0;
bottom: 0;
width: 100%;
overflow: hidden;
}
把 body 變成一個不能撐開,大小與窗口一致的塊,這樣就沒有東西可以滾動了。這里注意,不能把樣式賦給 html ,因為 html 無法設置 overflow-y 。
其實這樣,底下的內容已經不會跟著滾了,但問題肯定不會不那么簡單,因為還有一個問題
糾正顯示位置
添加上面樣式后,body 內的內容就會排列,顯示回最頂端的內容, 就像滾動條滾回最上面一樣,這當然不合理,所以我們要手動糾正。
首先需要將body內的內容包裹起來,姑且叫他 .bodyChild
var freezeScroll = (function ($bodyChild) {
var scrollTop, // 儲存凍結時頁面滾動位置
return {
freezeStart: function () {
scrollTop = $(document).scrollTop(); // 獲取滾動位置
$body.addClass('frozen')
$bodyChild.css('margin-top', -scrollTop + 'px') // 向上便宜
},
freezeEnd: function () {
$body.removeClass('frozen')
$(document).scrollTop(scrollTop) // 重新賦予滾動高度
$bodyChild.css('margin-top', '0px')
}
}
})( $('.bodyChild') ) // 自執(zhí)行,傳入一個body子元素
原理就是把里面的子元素用負值的 margin-top 偏移上去,模擬滾動條的位置,只要在浮層顯示隱藏的方法中調用 freezeScroll 的對應方法就可以瞞天過海拉!
任你浮層怎么滾,底下都紋絲不動!
寫到這里,別以為文章就要結束了,其實。。。。
iOS 下的彈性滾動問題
當我滿心歡喜解決了滾動冒泡問題后,上真機測試,安卓沒毛病絲滑流暢,然而到了 iOS 就 GG 了,遮罩層的滾動效果相當生澀,就是只要當手指抬起,內容就不再滾動了,正常的慣性完全消失。
又是一頓搜索,發(fā)現(xiàn) iOS 默認只會在 body 上添加慣性滾動效果,懸浮層在 body 固定的情況下自然就不會有這個特性咯。那么可以這樣來解決:
給擁有滾動條的父元素添加 -webkit-overflow-scroll: touch 樣式,立馬滾動又變得絲滑流暢啦!
然而這并不是完美的,一般慣性滾動到盡頭(最上或最下),會有個回彈的動畫,但當懸浮層回彈完并停下來后,手再拉向盡頭,懸浮層不再跟隨,而是固定在邊緣,并且無法再被滾動。
經過我初步的驗證和猜測,發(fā)現(xiàn)了可能的原因,但是這個又很難描述,總結得簡單一點,就是當懸浮層停在最盡頭之后,直接拉動嘗試觸發(fā)回彈動畫的話,會觸發(fā)底下 html 的回彈(沒錯,又回到了冒泡的問題上),而懸浮層并不會動,并且,在底下的回彈動畫結束前,懸浮層也不能滾動。
至于這個問題的解決辦法,暫時還沒研究出來,我想應該還是得從阻止冒泡的方向入手,畢竟我們上面只是固定了 body 而沒有真正解決冒泡的問題,另一個方面可以從展示屏蔽 html 的回彈動畫入手,等我解決了問題我再回來補充。