问题
IOS设备有默认的橡皮筋效果
,如下。但是在有些情况下是不需要的,在阻止橡皮筋效果
的过程中就有了下面的过程。
案例代码如下,可以直接复制使用。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="transparent" content="true" />
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0;" name="viewport" />
<title>IOS禁止橡皮筋效果</title>
<style>
html, body {
margin: 0;
}
#root {
display: flex;
background-color: #fff;
width: 100vw;
height: calc(100vh - 20px);
padding: 10px;
}
.left, .right {
flex: 1;
height: 100%;
overflow: auto;
}
.right > div {
margin: 16px;
}
</style>
</head>
<body>
<div id="root">
<div class="left">
无滑动区域
</div>
<div class="right">
<div>滑动 1</div>
<div>滑动 2</div>
<div>滑动 3</div>
<div>滑动 4</div>
<div>滑动 5</div>
<div>滑动 6</div>
<div>滑动 7</div>
<div>滑动 8</div>
<div>滑动 9</div>
<div>滑动 10</div>
<div>滑动 11</div>
<div>滑动 12</div>
<div>滑动 13</div>
<div>滑动 14</div>
<div>滑动 15</div>
<div>滑动 16</div>
</div>
</div>
</body>
</html>
初始的效果如下
方案
方案1. JS禁止
<script>
document.body.addEventListener('touchmove', function (e) {
e.preventDefault();
}, {
passive: false
});
</script>
现象: 在webview和浏览器中都有效。但是这个禁用,是一棍子打死的效果,不仅禁用掉了橡皮筋效果
,页面内部所有元素都都不能滑动了,不合适。
进一步优化: touchmove
时可以计算当前元素是否可以滑动,如往下滑动到最底时再往下滑,就阻止掉,否者正常滑动。
结论:由于JS需要频繁的取值计算,效率不高,而且也不能保证计算过程无bug,就放弃了这个方案。
方案2. CSS 脱离文档流
/* 增加以下样式 */
body {
position: fixed;
top: 0;
left: 0;
}
现象:在webview和浏览器中都有效。因为脱离文档流了,首次渲染时已经计算好位置,外部页面无论如何滑动,都不影响页面内部的布局。
问题:并没有真正禁用橡皮筋效果
,它依旧在,只是外部透明了,用户看不到而已。而在橡皮筋效果
的过程中,用户感知不到,所以会有滑动失效的错觉,如下,会给用户感觉是bug,体验不太好,放弃。
方案3. CSS overscroll-behavior
该属性让你可以控制浏览器过度滚动时的表现 —— 也就是滚动到边界。具体效果参考张鑫旭的文章
body, .scroll-container {
overscroll-behavior: none;
}
现象:在浏览器中有效,在webview中无效。怀疑是兼容性问题,overscroll-behavior
属性在低版本浏览器中不兼容,而此webview
也获取不到版本信息,或许webview
就没有对overscroll-behavior
支持吧。放弃。
方案4. CSS overflow: hidden
/* 增加以下样式 */
html, body {
overflow: hidden;
}
现象:在webview和浏览器中都可以,橡皮筋效果
没有了,元素的滑动效果也没受到影响。目前没有什么问题,最终也选择了这个方案。效果如下
兼容性发生意外
经过测试,方案4在iPhone12和iPhone14机子上是有效的,在iPhone13上面是无效的,追加方案
/* 增加以下样式 */
html, body {
overscroll-behavior: none;
}
⚠️ 保险起见,还是需要把webview
的bounces
设置为false
,从根上阻止IOS默认效果。