本文为平时开发过程中在iOS(Safari)上遇到兼容性问题的总结和记录。

1、阻止页面被双击放大和双指缩放

一般我们禁止为了禁止页面缩放会使用meta标签并设置viewport

  1. <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-scalabelmin-scalemax-scale 的设置,对于ios10以后的Safari浏览器兼容,要开发者自己搞。有兴趣可以看这份官方文档:

iOS10新的交互行为

我个人认为这种做法就是个坑,乔布斯以前有句话:“消费者并不知道自己需要什么,直到我们拿出自己的产品,他们就发现,这是我要的东西。”对于开发者来说也是如此,现在SPA应用兴起,很多网页都是专门为移动端设计,不是专门设计的有移动端需求也会适配到移动端,怎么会让用户随意缩放影响自身使用体验呢?况且开发者都期望页面是无缩放的了,webkit却还故意忽略这些选项,实属坑。

兼容性代码:

阻止双击放大

  1. let lastTouchEnd = 0;
  2. document.addEventListener('touchstart', function(event) {
  3. if (event.touches.length > 1) {
  4. event.preventDefault();
  5. }
  6. });
  7. document.addEventListener('touchend', function(event) {
  8. const now = (new Date()).getTime();
  9. if (now - lastTouchEnd <= 300) {
  10. event.preventDefault();
  11. }
  12. lastTouchEnd = now;
  13. }, false);

阻止双指缩放

  1. document.addEventListener('gesturestart', function(event) {
  2. event.preventDefault();
  3. });

2、iPhone刘海机型背景覆盖

web移动端(iOS)兼容性指北 - 图1

设置meta时,content内增加viewport-fit=cover

完整代码:

  1. <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浏览器(如图),它的视口区域不是我们通常认为的那样。

web移动端(iOS)兼容性指北 - 图2

关于viewport的内容可以看这篇博客
浅说移动前端中 Viewport 和 Viewport units

通常我们用vhvw 单位给容器设置一个可自适应的宽高,比如将容器的高度设置为100vh,此时我们认为容器的高度是浏览器内容区的高度,这在桌面和绝大多数的安卓浏览器适用,但在iOS Safari和Android Chrome上,情况可能会有所改变,这些浏览器并没有将100vh高度调整为视口高度变化时屏幕可见部分,而是将100vh设置为浏览器的高度,于是在有地址栏和工具栏的情况下,页面内容将被遮挡(裁切)

在caniuse的issues中也说明了viewport units兼容性情况

所以,在移动端的适配问题上,尽量避免使用100vh来设定容器高度,改为通过js来获取当前浏览器的视口区域并设置到相应容器上。

方法是给html节点的style设置自定义属性,值为获取到的视口大小,然后在具体容器的css中使用calc()函数设置容器高度或宽度。

javascript

  1. const vh = window.innerHeight;
  2. document.documentElement.style.setProperty('--vh', `${vh}px`)
  3. window.addEventListener('resize', () => {
  4. const vh = window.innerHeight;
  5. document.documentElement.style.setProperty('--vh', `${vh}px`);
  6. });

CSS

  1. .layout {
  2. /*height: 100vh;*/
  3. height: calc(var(--vh, 1vh));
  4. }

当然,也不能忘记窗口大小改变使页面自适应

  1. window.addEventListener('resize', () => {
  2. const vh = window.innerHeight;
  3. console.log(vh);
  4. document.documentElement.style.setProperty('--vh', `${vh}px`)
  5. })

4、阻止“橡皮筋”效果

“橡皮筋”效果是指在iOS Safari上滚动内容区域,从上往下拉亦或者从底部往上拉时,页面跟随手指被整个拉走并出现浏览器底色,微信小程序和一些浏览器用从上往下拉的方式实现便捷刷新。

不想要这种效果怎么办:

  1. 阻止window滚动;
  2. 开启容器滚动;(需要滚动时)
  3. 开启硬件加速;
  4. 阻止滚动越界;

阻止页面滚动

整个页面都不会有滚动了。

  1. window.addEventListener('touchmove', function (e) {
  2. e.preventDefault();
  3. }, {passive: false});

要加{passive:false}否则在iOS上不起作用,因为iOS Safari不会阻止默认页面滚动。这句话也单纯用来兼容iOS。

详细了解passive

开启容器滚动

一定要阻止冒泡。

  1. const content = document.querySelector('.content' );
  2. content?.addEventListener('touchmove',e => {
  3. e.stopPropagation();
  4. },{passive:false,capture:false});

开启硬件加速

关键属性-webkit-overflow-scrolling

忘了在哪里看到的了,这个属性可以触发浏览器的硬件加速,如果没有这个属性,那么滑动的过程会很卡,一抖一抖的掉帧严重,甚至带动整个页面移动。本身它的作用是启用滑动回弹效果,使滑动更流畅。

取值:

  • auto:使用普通滚动,手指从触摸屏离开滚动即停止;
  • touch:使用具有回弹效果的滚动, 当手指从触摸屏上移开,内容会继续保持一段时间的滚动效果,继续滚动的速度和持续的时间和滚动手势的强烈程度成正比。
  1. .content {
  2. overflow: auto;
  3. -webkit-overflow-scrolling: touch;
  4. }

阻止滚动越界

当滚动到页面顶部或底部时,手指离开停下,再继续向下向上滑动,就会出现滚动越界现象,此时需要进行滚动修复,阻止继续滚动带动整个页面移动。

  1. content?.addEventListener('touchmove', e => {
  2. if(content.scrollTop <= 0){
  3. content.scrollTop = 1
  4. }else if(content.scrollTop + content.clientHeight >= content.scrollHeight) {
  5. content.scrollTop = content.scrollHeight - content.clientHeight - 1;
  6. }
  7. // 别忘了阻止冒泡
  8. e.stopPropagation();
  9. },{passive:false,capture:false});

将持续更新。。。