移动端问题处理

键盘弹出收起问题

ios 和 android 在输入框 focus 时会自动触发键盘弹起,但视图表现不一致;当键盘收起时,表现也不一致

  • ios 问题
    • 键盘弹出时,不会改变视图的高度、只会让 scrolltop 变化,页面可以滚动,滚动最大是键盘的高度。当弹出键盘时页面已经滚动到最底部,scrolltop 为键盘高度,因此难以获取键盘真实高度。如果页面上有吸底按钮,按钮会被顶起。
    • 键盘收起或输入框以外被点击,输入框失焦,触发 blur 事件,键盘收起时,页面底部会出现空白区域。
  • android 问题
    • 键盘弹出时,影响页面高度,如果页面上有吸底按钮,按钮会被顶起。输入框如果位置偏低,可能会被键盘挡住。
    • 键盘收起时,影响页面高度,输入框不会失去焦点、不触发 blur 事件。只有输入框以外被点击,才会失焦触发 blur 事件

解决方法

  • 在 onfocus 事件中处理键盘弹出后的逻辑
  • ios 在 onblur 事件中处理键盘收起后的补充逻辑
  • android 监听 clientheight,在 onresize 事件中处理补充逻辑

mobile 端:

Javascript
const ua = window.navigator.userAgent.toLowerCase();
const isIOS = /iphone|ipad/.test(ua)
const isAndroid = /android/.test(ua)

handleInputFocus() {
  if (!this.isAndroid) {
    this.focused = true
    this.scrolled = false 
  }
},
 handleInputBlur() {
   if (!this.isAndroid) {
    this.focused = false
    this.scrolled = ture
    setTimeout(() => { // 避免还有其他输入框在 input
      if (this.scrolled) {
        window.scroll(0, 0)     
      }    
    }, 50)
   }
  },
   
 const originHeight = docuemnt.bofy.clientHeight
 onResize() {
 	if (this.isAndroid) {
    const resizeHeight = document.body.clientHeight
    if (resizeHeight < originHeight) {
    const activeElement = document.activeElement
      activeElement.scrolIntoView({ block: 'center'})
    } else {
      this.focused = !this.focused    
    }
  }
 }

ipad iOS9 flex 布局默认值问题

flex 布局如果写成简写 flex: 1 ,flex-grow 会为 1,但flex-shrink 会取其默认值1,当内部元素宽度之和大于容器的时候会发生收缩。

如果希望不收缩需要加上:

CSS
flex-shrink:0;

图片尺寸小数点像素问题

如果直接通过 img 加载图片, 设置 width、height 时 rem 可能会计算出小数,导致图片尺寸不一致。

解决方法

通过背景图加载图片,容器区块尺寸至少要等于(或者略大于)图片尺寸, background-size: contain  让图片完全放下,即便区块尺寸可能计算出小数像素,但 contain 的背景图长宽比不会收到到小数点影响。

比如 33.4px - 20.7 px 容器的背景图和 33.7px - 20.4 px容器的背景图,如果是同一张原尺寸 33.5 - 20.5 的contain 背景图,加载出来尺寸不会有差别

如果背景图特别小,可能 contain 也无法消除小数点差异,可以让容器区块尺寸比图片实际尺寸稍微大一点,留一点边。

滑动卡顿

CSS
-webkit-overflow-scrolling: touch;
overflow-scrolling: touch;

1px border

先写大像素的,比如 2px、4px,然后 transform: scale(0.5) or transform: scale(0.25)  调整

刘海屏兼容

https://developer.apple.com/design/human-interface-guidelines/ios/visual-design/adaptivity-and-layout/

image.png

现状

1、设置 页面全屏 <meta name="apple-mobile-web-app-capable" content="yes"> 页面高度不包括刘海屏

image.png

2、但页面如果滚动是可以进入刘海屏区域的

解决方案

1、viewport-fit to cover

CSS
<meta name='viewport' content='initial-scale=1, viewport-fit=cover'>

2、css env variables

image.png

同时需要避开状态栏等区域,让内容在 safe area 中,但不同设备需要避开的尺寸不一样,比如刘海区 44px 普通状态栏 20px,所以 ios 11 webkit 引入了 new CSS function env() (ios 11 开始是 constant() , safari 41 和 ios 11.2 beta 之后改成 env() ,老机器需要 fallback 兼容 )

以及四个预先定义好的css Environment Variables

  • safe-area-inset-left
  • safe-area-inset-right
  • safe-area-inset-top
  •  safe-area-inset-bottom

所以 constant()  被换成 env()  是可以理解的,因为这四个值即使在同一个机器上也不是固定的,比如页面滑动时,top 和 bottom 的值会有变化,从而才有渐变动画效果

CSS
.page {
  padding: 12px;
  padding-top: env(safe-area-inset-top);
  padding-bottom: env(safe-area-inset-bottom);
}

iPhone X下constant(safe-area-inset-bottom)对应34px,constant(safe-area-inset-top)对应44px,刘海区域的实际高度是32px

如果需要兼容老机器:

CSS
:root{
	--origin-safe-area-inset-top: 12;
  --origin-safe-area-inset-bottom: 12;
}
@supports (width: env(safe-area-inset-top)){
  :root{
    --origin-safe-area-inset-top: env(safe-area-inset-top);
    --origin-safe-area-inset-bottom: env(safe-area-inset-bottom);
  }
}
.page {
  padding-top: var(--origin-safe-area-inset-top);
  padding-bottom: var(--origin-safe-area-inset-bottom);
}

3、min() and max()

如果需要支持横屏,会使用到safe-area-inset-leftsafe-area-inset-right,但问题这两个值在横屏时有安全距离,但竖屏时为 0。所以需要做一下处理:

CSS
@supports(padding: max(0px)) {
    .page {
        padding-left: max(12px, env(safe-area-inset-left));
        padding-right: max(12px, env(safe-area-inset-right));
    }
}

4、透明头

通常会有负margin 的方法让主体吸顶,这个 负margin 值是页头高度加上 状态栏 20px,对于 iphonex,则需要加上 safe-area-inset-top 的值:

CSS
:root {
	--page-header-height: 100;
}
:root{
  --header-top: calc(var(----page-header-height) + 20px);
}
@supports (height: env(safe-area-inset-top)){
  :root{
    --header-top: calc(var(----page-header-height) + env(safe-area-inset-top));
  }
}
.content {
  padding-top: var(--header-top);
  margin-top: calc(0px - var(--header-top));
}

5、注意点

  • viewport-fit 设成 cover 之后, height: 100%  无法撑满整个窗口,实际页面被上提了 safe-area-inset-top ,一定要用 height: 100vh 。如果有吸底按钮,一定要用 min-height: 100vh