跳到主要内容

移动端问题

使用vh​

  • 在移动端使用vh 单位,主要是因为移动浏览器的地址栏和工具栏会动态隐藏/显示,导致视口高度变化。

底部安全区域问题​

  • iphoneX以上会出现底部安全区域
  • 对于动态高度的计算,需要处理安全区域问题
js
padding-top: constant(safe-area-inset-top);
padding-top: env(safe-area-inset-top)
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);

示例

js
// 处理安全区域,底部安全区域
const height = computed(() => {
const safeAreaTop = 'env(safe-area-inset-top, 0px)'
const safeAreaBottom = 'env(safe-area-inset-bottom, 0px)'
if (showBottomAction.value) {
return `calc(100vh - ${safeAreaTop} - ${safeAreaBottom} - ${px2rem(180)})`
} else {
return `calc(100vh - ${safeAreaTop} - ${safeAreaBottom})`
}
})

env用法​

env(safe-area-inset-top, 10px) 中的第二个参数 0px 是回退值(fallback value)。

  • 当浏览器不支持 safe-area-inset-top 环境变量时

  • 或者当前设备没有安全区域(比如非刘海屏设备)时

  • 就会使用回退值 10px

window.innerHeight问题​

  • 在内嵌的app中,是全屏的,需要加上app的状态栏的高度

移动端 Webview 兼容性 (滑动重复渲染问题)​

  • 在某些 iOS 设备上,当一个页面本身不可滚动时(比如你的页面是用绝对定位和固定定位布局的),用户的上下滑动操作(尤其是在页面顶部或底部快速滑动)有时会被 Webview 误解。

    iOS 的 Webview 可能会把这个滑动操作当成是“下拉刷新”或者“侧滑返回”这样的原生手势。如果你的 App 外壳处理了这个手势并重新加载了页面,就会出现你看到的“渲染了多个组件 的情况,本质上是页面被重复加载或堆叠了。

  • 问题根源:在 iOS 上,当页面内容本身不可滚动时,用户的滑动操作(特别是快速的上下滑动)有时会被 Webview 误解为“下拉刷新”或“边缘滑动手势”,从而触发了页面的重新加载或导航,导致你看到的组件重复渲染。

解决

  • 外层容器设置
    • contain:刹车 + 筑墙。它既阻止了原生的边界效果(如“下拉刷新”),也阻止了滚动事件传递给父元素(滚动链)
      • 告诉浏览器:“当这个元素在垂直方向上滚动到尽头时,请刹车,不要把滚动事件传递出去,也不要触发任何原生的边界效果
      • 会阻止浏览器因为用户的滑动操作而触发原生的下拉刷新功能,从而解决了你的页面被重复渲染的问题。
    • none:只刹车,不筑墙。它只阻止了原生的边界效果,但不会阻止滚动事件传递给父元素
css
overscroll-behavior-y: contain;
  • 简单来说,就是用户快速滑动,禁止触发原生的下拉刷新功能,避免刷新页面

移动端粘贴方法问题​

  • navigator.clipboard.readText()
    • 必须是 HTTPS
    • Safari(iOS)可能不兼容,有些版本不支持
  • 读取剪贴板 = 潜在隐私泄露,因此在移动端不允许页面主动读取用户剪贴板

弹窗遮罩滚动穿透问题​

不要只靠 overflow: hidden 最稳妥、跨端一致性最好的是:position: fixed 锁 body + 记录滚动位置

  • 当弹窗显示的时候,设置body为hidden,可解决滚动穿透问题
js
watch(() => props.visible, (val) => {
if (val) {
document.body.style.overflow = 'hidden'
}
else {
document.body.style.overflow = ''
}
})

onUnmounted(() => {
document.body.style.overflow = ''
})
  • 修复滚动穿透问题。overflow: hidden 在某些移动端浏览器(特别是 iOS Safari)上不够可靠,需要使用 position: fixed 方案
js
export default function useBodyScroll() {
// 记录滚动位置
let scrollPosition = 0
// 禁用滚动穿透
const disableBodyScroll = () => {
if (!process.client)
return

scrollPosition = window.pageYOffset || document.documentElement.scrollTop
document.body.style.position = 'fixed'
document.body.style.top = `-${scrollPosition}px`
document.body.style.width = '100%'
document.body.style.overflow = 'hidden'
}

// 恢复滚动
const enableBodyScroll = () => {
if (!process.client)
return

document.body.style.position = ''
document.body.style.top = ''
document.body.style.width = ''
document.body.style.overflow = ''
window.scrollTo(0, scrollPosition)
}

return {
disableBodyScroll,
enableBodyScroll,
}
}

overflow: hidden​

  • 在移动端(尤其 iOS)极不稳定
  • 不靠谱,只适合 PC

常见问题:

  • iOS Safari 仍然可以滚动(橡皮筋回弹)
  • 内部元素滚动时会“带着 body 一起动”
  • touchmove 仍然能触发页面滚动

position: fixed​

  • 真正锁死 body
  • iOS / Android / WebView / 微信 全部生效
  • 不受橡皮筋影响
  • 是各大 UI 库的最终选择

需要处理的问题

  • 页面会“跳回顶部”
  • 关闭弹窗需要恢复原滚动位置

语言切换问题​

  • navigator.languages 返回的是浏览器的语言设置,但在移动端,这个设置默认是跟随手机系统语言的