本文为平时开发过程中在iOS(Safari)上遇到兼容性问题的总结和记录。
1、阻止页面被双击放大和双指缩放
一般我们禁止为了禁止页面缩放会使用meta标签并设置viewport
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no,viewport-fit=cover">
但只用这个方法在ios10以后就不行了,webkit官方认为现在的网页似乎都喜欢设置user-scalable=no
使用户无法缩放页面,这会使一些页面因无法正常缩放而无法看清字体,比如一些为pc设计的页面在移动端字体看起来会非常小。所以他们忽略了user-scalabel
、min-scale
、max-scale
的设置,对于ios10以后的Safari浏览器兼容,要开发者自己搞。有兴趣可以看这份官方文档:
我个人认为这种做法就是个坑,乔布斯以前有句话:“消费者并不知道自己需要什么,直到我们拿出自己的产品,他们就发现,这是我要的东西。”对于开发者来说也是如此,现在SPA应用兴起,很多网页都是专门为移动端设计,不是专门设计的有移动端需求也会适配到移动端,怎么会让用户随意缩放影响自身使用体验呢?况且开发者都期望页面是无缩放的了,webkit却还故意忽略这些选项,实属坑。
兼容性代码:
阻止双击放大
let lastTouchEnd = 0;
document.addEventListener('touchstart', function(event) {
if (event.touches.length > 1) {
event.preventDefault();
}
});
document.addEventListener('touchend', function(event) {
const now = (new Date()).getTime();
if (now - lastTouchEnd <= 300) {
event.preventDefault();
}
lastTouchEnd = now;
}, false);
阻止双指缩放
document.addEventListener('gesturestart', function(event) {
event.preventDefault();
});
2、iPhone刘海机型背景覆盖
设置meta
时,content
内增加viewport-fit=cover
完整代码:
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no,viewport-fit=cover">
3、视口适配
一般我们认为浏览器的视口(viewport)区域就是除了上面地址栏以及底部按钮区,这在桌面浏览器上是正确的,但在移动端,它要复杂很多,比如iOS的Safari浏览器(如图),它的视口区域不是我们通常认为的那样。
关于viewport的内容可以看这篇博客
《浅说移动前端中 Viewport 和 Viewport units》
通常我们用vh
、vw
单位给容器设置一个可自适应的宽高,比如将容器的高度设置为100vh
,此时我们认为容器的高度是浏览器内容区的高度,这在桌面和绝大多数的安卓浏览器适用,但在iOS Safari和Android Chrome上,情况可能会有所改变,这些浏览器并没有将100vh高度调整为视口高度变化时屏幕可见部分,而是将100vh设置为浏览器的高度,于是在有地址栏和工具栏的情况下,页面内容将被遮挡(裁切)
在caniuse的issues中也说明了viewport units兼容性情况
所以,在移动端的适配问题上,尽量避免使用100vh来设定容器高度,改为通过js来获取当前浏览器的视口区域并设置到相应容器上。
方法是给html节点的style设置自定义属性,值为获取到的视口大小,然后在具体容器的css中使用calc()
函数设置容器高度或宽度。
javascript
const vh = window.innerHeight;
document.documentElement.style.setProperty('--vh', `${vh}px`)
window.addEventListener('resize', () => {
const vh = window.innerHeight;
document.documentElement.style.setProperty('--vh', `${vh}px`);
});
CSS
.layout {
/*height: 100vh;*/
height: calc(var(--vh, 1vh));
}
当然,也不能忘记窗口大小改变使页面自适应
window.addEventListener('resize', () => {
const vh = window.innerHeight;
console.log(vh);
document.documentElement.style.setProperty('--vh', `${vh}px`)
})
4、阻止“橡皮筋”效果
“橡皮筋”效果是指在iOS Safari上滚动内容区域,从上往下拉亦或者从底部往上拉时,页面跟随手指被整个拉走并出现浏览器底色,微信小程序和一些浏览器用从上往下拉的方式实现便捷刷新。
不想要这种效果怎么办:
- 阻止window滚动;
- 开启容器滚动;(需要滚动时)
- 开启硬件加速;
- 阻止滚动越界;
阻止页面滚动
整个页面都不会有滚动了。
window.addEventListener('touchmove', function (e) {
e.preventDefault();
}, {passive: false});
要加{passive:false}
否则在iOS上不起作用,因为iOS Safari不会阻止默认页面滚动。这句话也单纯用来兼容iOS。
开启容器滚动
一定要阻止冒泡。
const content = document.querySelector('.content' );
content?.addEventListener('touchmove',e => {
e.stopPropagation();
},{passive:false,capture:false});
开启硬件加速
关键属性-webkit-overflow-scrolling
忘了在哪里看到的了,这个属性可以触发浏览器的硬件加速,如果没有这个属性,那么滑动的过程会很卡,一抖一抖的掉帧严重,甚至带动整个页面移动。本身它的作用是启用滑动回弹效果,使滑动更流畅。
取值:
- auto:使用普通滚动,手指从触摸屏离开滚动即停止;
- touch:使用具有回弹效果的滚动, 当手指从触摸屏上移开,内容会继续保持一段时间的滚动效果,继续滚动的速度和持续的时间和滚动手势的强烈程度成正比。
.content {
overflow: auto;
-webkit-overflow-scrolling: touch;
}
阻止滚动越界
当滚动到页面顶部或底部时,手指离开停下,再继续向下向上滑动,就会出现滚动越界现象,此时需要进行滚动修复,阻止继续滚动带动整个页面移动。
content?.addEventListener('touchmove', e => {
if(content.scrollTop <= 0){
content.scrollTop = 1
}else if(content.scrollTop + content.clientHeight >= content.scrollHeight) {
content.scrollTop = content.scrollHeight - content.clientHeight - 1;
}
// 别忘了阻止冒泡
e.stopPropagation();
},{passive:false,capture:false});
将持续更新。。。