移动端网页避坑指南

DOM touch事件不触发

移动端浏览器可能会对手指点击做一些优化,在点击某个元素时,如果该元素没有绑定点击事件,会优先查找附近的可点击元素,然后触发附近元素的点击事件,也因此会导致触摸事件被周围元素的点击事件“吞掉”,解决方法是为该元素绑定一个空的点击事件,防止浏览器默认触发周围元素事件。

vue
<div @click="" @touchstart="onTouchStart"></div>

iOS Safari 100vh问题

iOS Safari和部分其他浏览器会有底部导航栏,导致这部分高度挤占了原本的可视区域宽度,在设置css高度为100vh时,元素的实际高度会高于实际显示区域,导致滚动条的出现,影响用户体验,可以通过手动监听屏幕宽高变化的形式来设置高度,建议设置为css变量,使用体验极好。

typescript
const getWindowSize = () => ({
    innerHeight: window.innerHeight,
    innerWidth: window.innerWidth,
  });

export const registerActualWindowSize = () => {
  const updateSize=()=>{
    const size = getWindowSize();
    document.documentElement.style.setProperty('--actual-window-width', `${size.innerWidth}px`);
  document.documentElement.style.setProperty('--actual-window-height', `${size.innerHeight}px`);
  };
  updateSize();
  window.addEventListener('resize', updateSize)
};

CSS使用:

scss
div{
    height: var(--actual-window-width);
    // css变量可以使用calc、max等计算方法
}

移动端浏览器各式导航栏兼容问题

iOS Safari和部分浏览器可能会有默认的下拉刷新行为,可以通过css部分关闭这种默认行为

scss
html{
  overflow: hidden;
}

这样同样也会影响浏览器的导航栏的其他行为,例如部分浏览器在滚动时会自动收起顶部或者底部导航栏,如果设置了这个css后会导致这样的默认行为失效

如果希望在某些情况下允许默认行为,例如横屏适配时,可以加入媒体查询

scss
@media (max-height: 400px) {
// or (orientation: landscape)
  html{
  overflow: auto;
}
}

CSS border白边问题

有时候使用border来设置选中状态的轮廓的时候,在移动端或者某些分辨率的设备上会导致border与内容间出现一条白色空隙,解决方法是不使用border来设置边框,而使用box-shadow或者伪元素,也可以解决设置边框后导致内部空间被边框挤占而产生的内部元素大小变化。

scss
div{
  position: relative;
  &:after{
    content:'';
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    border: 2px solid red;
  }
}

移动端浏览器网页缩放问题

建议所有网页都设置此meta,防止浏览器意外缩放以及其他默认行为导致的网页缩放样式问题

html
<meta
      name="viewport"
      content="width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover"
    />

避免双击导致的缩放:

https://developer.mozilla.org/en-US/docs/Web/CSS/touch-action

scss
* {
  touch-action: manipulation;
}

一些CSS技巧

scss
html{
    // 去除iOS Safari点击元素默认的高亮颜色
    -webkit-tap-highlight-color: transparent;
    // 禁止长按选中文字,大部分情况下都不需要
    :not(input) {
        user-select: none;
        -webkit-user-select: none;
    }
    // 修改滚动条样式,仅部分浏览器生效
    ::-webkit-scrollbar {
        width: 4px;
        height: 4px;
    }
    ::-webkit-scrollbar-thumb {
        background-color: #0003;
        border-radius: 4px;
        transition: all 0.2s ease-in-out;
    }
    ::-webkit-scrollbar-track {
        border-radius: 4px;
    }
}

iOS Safari 视频不自动展示的问题

iOS safari默认情况下视频是不会自动load的,也因此显示的时候是一片空白,或者导致骨架屏一直loading,解决方法是手动调用加载

typescript
// autoLoad.ts
// 使用自定义指令
import type { Directive } from 'vue';

export const vAutoLoad: Directive = {
  mounted: (el) => {
    el?.load?.();
  },
};
// <video v-auto-load src="xxx" />

同时骨架屏也不要使用slot,因为slot里的DOM只会在骨架屏结束后才会生成,会导致无法触发mount事件,需要更改布局来实现骨架屏loading

vue
<el-skeleton v-if="loading" loading></el-skeleton>
<video v-show="!loading" v-auto-load src="xxx" @canplaythrough="loading=true">

如果涉及到src改变,可以加入key值改动

vue
<el-skeleton v-if="loading" loading></el-skeleton>
<video v-show="!loading" v-auto-load :key="src" :src="src" @canplaythrough="loading=true">

iOS Safari 某些css样式与Chrome表现差异

  1. Safari outline圆角不生效

scss
div{
  border-radius: 8px;
  outline: 2px solid red;
  // iOS上 outline 会没有圆角
  // 使用box-shadow或者border代替
  border: 2px solid red;
  box-shadow: 0 0 0 2px red;
}

iOS Safari 下载弹窗强制中断问题

这个问题是最严重的,一般出现在网站提供点击下载的功能的时候,业务往往会要求点击下载之后弹出一些引导弹窗,或者发起某个请求,但是safari会有一个二次确认的弹窗,在这个弹窗弹出时,会强制中断所有的请求,包括图片的url请求、fetch发送的请求等,而且对于img标签的请求,完全检测不到任何报错,排查这个问题简直让人发狂,Apple独断专横又技不如人的傲慢尤其在此显得格外恶心。目前没有办法解决这个问题,对于图片尚可以使用在下载前预加载的方式来绕过,而普通请求则完全没有办法,只能更改业务逻辑。F**k Apple