解决移动端网页开发“滚动穿透”问题

问题背景

  在开发移动端网页的过程中,经常会以弹层的形式来展示信息给用户。在弹层开发过程中经常会遇到这样一个问题:当用户手指在弹层上滑动时,弹层下面的内容也会跟随手指的滑动一起滚动。这就是移动端网页的”滚动穿透”问题。

问题产生原因

  当用户手指在弹层上滑动时,默认触发了浏览器的”scroll”事件,事件冒泡至body元素,于是就产生了”滚动穿透”效果。

问题解决方案

  针对移动端页面”滚动穿透”的问题,目前主要有两种解决方案:
  (1)在touchmove事件处理函数中使用preventDefault()阻止事件的默认动作。当用户手指在弹层上滑动时,浏览器不再触发”scroll”事件,”滚动穿透”现象也就不再发生。但是该解决方案不适用于弹层需要实现滚动的场景。
  (2)当发起弹层时,设置body元素的position属性为fixed,并且设置body元素向上的偏移量等于此时其已经滚动的距离;当关闭弹层时,恢复body元素的相关属性即可。该方案与方案(1)相比,可以适用于弹层包含滚动的场景,是一个相对完美的解决方案。该方案的核心处理函数的示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 发起弹层时调动
function fixBody() {
var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
document.body.style.position = 'fixed';
document.body.style.top = -scrollTop + 'px';
// 设置body宽度等于viewport的宽度,防止body子元素宽度大于视口宽度时布局错乱
document.body.style.width = '100%';
}
// 关闭弹层时调用
function relaxBody() {
// 清空position属性
document.body.style.position = '';
// 恢复scrollTop
document.body.scrollTop = document.documentElement.scrollTop = -parseFloat(document.body.style.top);
// 清空top属性
document.body.style.top = '';
// 清空width属性
document.body.style.width = '';
}

小提示

  对于PC端页面来说,可以设置body元素的overflow属性的值为hidden来解决弹层的”滚动穿透”问题。该方案只适用于PC端页面,不适用于移动端页面。