移動端當有fixed蒙層遮罩時,在屏幕上滑動能夠滑動背景下的內容,這就是滾動穿透問題。
1、問題還原
<!--html結構-->
<body>
<div>內容部分</div>
<div>彈出框</div>
</body>
css就省略了,內容部分是超過一屏的長度的,彈出框采用絕對定位展示在可視區域的固定位置,遮罩是加在body元素上的。滑動頁面會出現滑動穿透的問題,遮罩下的內容會跟著滑動。
2、問題分析
出現滑動穿透的問題是滾動條在body元素上,而滑動的時候body自然是可以響應的。那么將結構改變一下:
<!--html結構-->
<body>
<div class="content">
<div>內容部分</div>
<div>彈出框</div>
</div>
</body>
為了不讓滾動條加在body元素上,還需要做如下處理:
body {
height: 100%;
}
.content {
height: 100%;
overflow: auto;
}
. overflow-hidden {
overflow: hidden
}
在彈出框出現時需要把overflow-hidden
類加在根div元素上。彈出消失時移除。
3、總結
這里po一個搜到的常規解決穿透的方案:
解決方案原理:禁用body的滾動條,由于滾動條的位置會丟失,所以需要在展示彈窗之前保存滾動條的位置,隱藏彈窗時恢復滾動條的位置。
首先定義class來禁用滾動條
.modal-open {
position:fixed;
height: 100%;
}
然后完成保存并恢復滾動條的工作:
/**
* ModalHelper helpers resolve the modal scrolling issue on mobile devices
* https://github.com/twbs/bootstrap/issues/15852
* requires document.scrollingElement polyfill https://github.com/yangg/scrolling-element
*/
var ModalHelper = (function(bodyCls) {
var scrollTop;
return {
afterOpen: function() {
scrollTop = document.scrollingElement.scrollTop;
document.body.classList.add(bodyCls);
document.body.style.top = -scrollTop + 'px';
},
beforeClose: function() {
document.body.classList.remove(bodyCls);
// scrollTop lost after set position:fixed, restore it back.
document.scrollingElement.scrollTop = scrollTop;
}
};
})('modal-open');
然后在彈出層顯示時調用ModalHelper.afterOpen()
,在隱藏彈出層時調用ModalHelper.beforeClose()
。
不過這種方式較麻煩了,能夠采用簡單的方式解決還是最好的。
4、兩個兼容問題
1.在IOS上慣性滑動失效
.content {
-webkit-overflow-scrolling: touch; /* 解決在IOS上滾動慣性失效的問題 */
}
2.在IOS上非交互性元素的點擊事件失效
非交互性元素:沒有顯式綁定點擊等事件處理函數的元素。
簡單的解決方案是給元素添加cursor: pointer
使之成為交互元素。
但是這又會帶來另一個問題:所有設置cursor: pointer
的元素在webkit內核的瀏覽器中點擊時會有藍色背景,可以如下設置來取消藍色背景:
*{
-webkit-tap-highlight-color: transparent; /* 解決設置cursor:pointer的元素點擊出現藍色背景的問題 */
}
后話
在ios中有一個默認的效果是雙擊title回到頂部,如果滾動條不是在body元素上,那么這個效果將失效。