H5移动端常见问题

h5 常见问题

1. H5 页面窗口自动调整到设备宽度,并禁止用户缩放页面

一、HTML 页面结构
// width    设置 viewport 宽度,为一个正整数,或字符串 'device-width'
// height   设置 viewport 高度,一般设置了宽度,会自动解析出高度,可以不用设置
// initial-scale    默认缩放比例,为一个数字,可以带小数
// minimum-scale    允许用户最小缩放比例,为一个数字,可以带小数
// maximum-scale    允许用户最大缩放比例,为一个数字,可以带小数
// user-scalable    是否允许手动缩放
<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no" />
二、JS 动态判断
var phoneWidth =  parseInt(window.screen.width);
var phoneScale = phoneWidth/640;
var ua = navigator.userAgent;
if (/Android (\d+\.\d+)/.test(ua)){
      var version = parseFloat(RegExp.$1);
      if(version>2.3){
          document.write('<meta name="viewport" content="width=640, minimum-scale = '+phoneScale+', maximum-scale = '+phoneScale+', target-densitydpi=device-dpi">');
      }else{
          document.write('<meta name="viewport" content="width=640, target-densitydpi=device-dpi">');
      }
  } else {
      document.write('<meta name="viewport" content="width=640, user-scalable=no, target-densitydpi=device-dpi">');
}

2. 移动端如何定义字体 font-family

@ -------------------------------中文字体的英文名称---------------------------------
@ 宋体       SimSun
@ 黑体       SimHei
@ 微信雅黑    Microsoft Yahei
@ 微软正黑体  Microsoft JhengHei
@ 新宋体      NSimSun
@ 新细明体    MingLiU
@ 细明体      MingLiU
@ 标楷体      DFKai-SB
@ 仿宋        FangSong
@ 楷体        KaiTi
@ 仿宋_GB2312 FangSong_GB2312
@ 楷体_GB2312 KaiTi_GB2312  
@
@ 说明:中文字体多数使用宋体、雅黑,英文用 Helvetica 
body { font-family: Microsoft Yahei,SimSun,Helvetica; }

3. 移动端字体单位font-size选择px还是rem

// 如需适配多种移动设备,建议使用rem。以下为参考值(浏览器默认字号为16px):
html { font-size: 62.5%; }   //10/16 = 62.5%
//设置12px字体   这里注意在rem前要加上对应的px值,解决不支持rem的浏览器的兼容问题,做到优雅降级
body { font-size:12px; font-size:1.2rem; }  

4. 取消input在ios下,输入的时候英文首字母的默认大写

<input autocapitalize="off" autocorrect="off" />

5. 手机拍照和上传图片

//IOS有拍照、录像、选取本地图片功能,部分Android只有选择本地图片功能。Winphone不支持
<input type="file" accept="images/*" />
<input type="file" accept="video/*" />

6. audio元素和video元素在ios和andriod中无法自动播放

//音频,写法一
<audio src="music/bg.mp3" autoplay loop controls>你的浏览器还不支持哦</audio>

//音频,写法二
<audio controls="controls">	
	<source src="music/bg.ogg" type="audio/ogg"></source>
	<source src="music/bg.mp3" type="audio/mpeg"></source>
	优先播放音乐bg.ogg,不支持在播放bg.mp3
</audio>

//JS绑定自动播放(操作window时,播放音乐)
$(window).one('touchstart', function(){
	music.play();
})

//微信下兼容处理
document.addEventListener("WeixinJSBridgeReady", function () {
    music.play();
}, false);

//小结
//1.audio元素的autoplay属性在IOS及Android上无法使用,在PC端正常
//2.audio元素没有设置controls时,在IOS及Android会占据空间大小,而在PC端Chrome是不会占据任何空间

7. 重力感应事件

// 运用HTML5的deviceMotion,调用重力感应事件
if(window.DeviceMotionEvent){
	document.addEventListener('devicemotion', deviceMotionHandler, false)
}	

var speed = 30;
var x = y = z = lastX = lastY = lastZ = 0;
function deviceMotionHandler(eventData){
	var acceleration = event.accelerationIncludingGravity;
	x = acceleration.x;
	y = acceleration.y; 
	z = acceleration.z;
	if(Math.abs(x-lastX)>speed || Math.abs(y-lastY)>speed || Math.abs(z-lastZ)>speed ){
		//这里是摇动后要执行的方法 
		yaoAfter();
	}
	lastX = x;
	lastY = y;
	lastZ = z;
}

function yaoAfter(){
	//do something
}

8. 打电话发短信写邮件怎么实现

一、打电话
<a href="tel:0755-10086">打电话给:0755-10086</a>
二、发短信,Winphone 系统无效
<a href="sms:10086">发短信给: 10086</a>
三、写邮件
注:在添加这些功能时,第一个功能以"?"开头,后面的以"&"开头
// 1.普通邮件
<a href="mailto:863139978@qq.com">点击我发邮件</a>
// 2.收件地址后添加 ?cc= 开头,可添加抄送地址(Android 存在兼容问题)
<a href="mailto:863139978@qq.com?cc=zhangqian0406@yeah.net">点击我发邮件</a>
// 3.跟着抄送地址后,写上 &bcc=,可添加密件抄送地址(Android 存在兼容问题)
<a href="mailto:863139978@qq.com?cc=zhangqian0406@yeah.net&bcc=384900096@qq.com">点击我发邮件</a>
// 4.包含多个收件人、抄送、密件抄送人,用分号( ; )隔开多个邮件人的地址
<a href="mailto:863139978@qq.com;384900096@qq.com">点击我发邮件</a>
// 5.包含主题,用 ?subject=
<a href="mailto:863139978@qq.com?subject=邮件主题">点击我发邮件</a>
// 6.包含内容,用 ?body=; 如内容包含文本,使用 %0A 给文本换行 
<a href="mailto:863139978@qq.com?body=邮件主题内容%0A腾讯诚信%0A期待您的到来">点击我发邮件</a>
// 7.内容包含链接,含 http(s):// 等的文本自动转化为链接
<a href="mailto:863139978@qq.com?body=http://www.baidu.com">点击我发邮件</a>
// 8.内容包含图片(PC 不支持)
<a href="mailto:863139978@qq.com?body=![](images/1.jpg)">点击我发邮件</a>
// 9.完整示例
<a href="mailto:863139978@qq.com;384900096@qq.com?cc=zhangqian0406@yeah.net&bcc=993233461@qq.com&subject=[邮件主题]&body=腾讯诚邀您参与%0A%0Ahttp://www.baidu.com%0A%0A![](images/1.jpg)">点击我发邮件</a>

9. iphone及ipad下输入框默认内阴影

input{
  -webkit-appearance:none;
}

10. 圆角bug,某些Android手机圆角失效

background-clip: padding-box;

11. video禁止全屏播放

<video x-webkit-airplay="true" webkit-playsinline="true" playsinline="true"></video>

12. 去除点击元素产生背景或边框

* { -webkit-tap-highlight-color: rgba(0,0,0,0); }

13. 禁止长按链接与图片弹出菜单

a,img{-webkit-touch-callout:none;}

14. 禁止用户选中图片或文字

body{-webkit-user-select: none}

15. 禁用webkit内核浏览器的文字大小调整功能

body{-webkit-text-size-adjust: none}

16. 去除表单元素默认样式

input{
  -webkit-appearance:none;
  outline:none;
}
// 添加这两行代码后,input的边框还是存在,若要去除,需要添加 border: none; 方可
input{
  -webkit-appearance:none;
  outline:none;
  border: none;
}

17. 改变输入框placeholder的颜色值

::-webkit-input-placeholder { color: #999; }
input:focus::-webkit-input-placeholder{ color:#999; }
  • line-height==height 在部分安卓手机不垂直居中,显示偏上
p{
  line-height: normal;
  padding: 10px 0;
}

18. 屏幕旋转的事件和样式

var resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize'
window.addEventListener(resizeEvt, function(){}, false)

//竖屏时样式
@media all and (orientation:portrait){   }
//横屏时样式
@media all and (orientation:landscape){   }

19. iOS中不支持"2000-01-01 00:00:00"格式,返回NaN

var time = "2000-01-01 00:00:00"
time = time.replace(/\-/g, "/");//将时间格式的'-'转成'/'形式,兼容iOS

20. iOS中:active点击态样式不生效

document.body.addEventListener('ontouchstart',function(){})

21. 当使用fixed添加图层蒙版时, 滚动屏幕会引起页面滚动, 可使用js在图层蒙版显示时,记录屏幕位置, 在关闭蒙版后,重新设置屏幕位置。

//获取元素的滚动位置
document.documentElement.scrollTop
//重设元素的滚动位置
document.documentElement.scrollTo(0,this.scrollTop)

// 上述方式可以重设元素的位置,但是还是可以滚动屏幕,如果图层蒙版为透明状,可以看到屏幕位置的变化, 可以在这个方案的基础上,重设屏幕滚动元素的样式 position top; fixed 、 top、 overflow: hidden =》 absolute、 top、 overflow: auto

22. 输入框被键盘挡住问题

window.addEventListener('resize', function() {
    if(
        document.activeElement.tagName === 'INPUT' ||
        document.activeElement.tagName === 'TEXTAREA' // 获得文档中获取焦点的元素
      ) {
        window.setTimeout(function() {
          if('scrollIntoView' in document.activeElement) {
            document.activeElement.scrollIntoView(); // 滚动当前元素到可见区域
          } else {
            document.activeElement.scrollIntoViewIfNeeded();
          }
        }, 0);
      }
});

23. 移动端 touch 事件(区分 webkit 和 winphone)

/* 当用户手指放在移动设备在屏幕上滑动会触发的 touch 事件 */
// 以下支持 webkit
touchstart ——当手指触碰屏幕时候发生。不管当前有多少只手指
touchmove ——当手指在屏幕上滑动时连续触发。通常我们再滑屏页面,会调用 event 的 preventDefault() 可以阻止默认情况的发生:阻止页面滚动
touchend ——当手指离开屏幕时触发
touchcancel ——系统停止跟踪触摸时候会触发。例如在触摸过程中突然页面 alert() 一个提示框,此时会触发该事件,这个事件比较少用
// TouchEvent 说明:
touches:屏幕上所有手指的信息
targetTouches:手指在目标区域的手指信息
changedTouches:最近一次触发该事件的手指信息
touchend 时,touches 与 targetTouches 信息会被删除,changedTouches 保存的最后一次的信息,最好用于计算手指信息
// 参数信息( changedTouches[0] )
clientX、clientY 在显示区的坐标
target:当前元素
// 事件响应顺序
ontouchstart  > ontouchmove  > ontouchend > onclick
// 以下支持 Winphone 8
MSPointerDown ——当手指触碰屏幕时候发生。不管当前有多少只手指
MSPointerMove ——当手指在屏幕上滑动时连续触发。通常我们再滑屏页面,会调用 css 的 html{-ms-touch-action: none;} 可以阻止默认情况的发生:阻止页面滚动
MSPointerUp ——当手指离开屏幕时触发

24. ios设备微信浏览器或者Safari中fixed定位的部分会跟随滑动跳动

//css
.header{
    width:100%;
    height:100px;
    position:absolute;
    left:0;
    top:0;
}
.footer{
    width:100%;
    height:100px;
    position:absolute;
    left:0;
    bottom:0; // 头部、尾部位置使用absolute属性设置
}
.main{
    width:100%;
    position:absolute;
    left:0;
    right:0;
    top:100px;
    bottom:100px; // 根据头部尾部占用的高度,设置top、bottom值
}

25. 移动端 click 屏幕产生 200-300ms 的延时响应

说明:移动设备上的 Web 网页是有 300ms 延迟的,玩玩会造成按钮点击延迟甚至是点击失效。
以下是历史原因,来源一个公司内一个同事的分享:
      2007 年苹果发布首款 iPhone 上 iOS 系统搭载的 Safari 为了将适用于PC 端上大屏幕的网页能比较好的展示在手机端上,使用了双击缩放( double tap to zoom )的方案,比如你在手机上用浏览器打开一个 PC 上的网页,你可能在看到页面内容虽然可以撑满整个屏幕,但是字体、图片都很小看不清,此时可以快速双击屏幕上的某一部分,你就能看清该部分放大后的内容,再次双击后能回到原始状态。
      双击缩放是指用手指在屏幕上快速点击两次,iOS 自带的 Safari 浏览器会将网页缩放至原始比例。
      原因就出在浏览器需要如何判断快速点击上,当用户在屏幕上单击某一个元素时候,例如跳转链接 <a href="#"></a>,此处浏览器会先捕获该次单击,但浏览器不能决定用户是单纯要点击链接还是要双击该部分区域进行缩放操作,所以,捕获第一次单击后,浏览器会先 Hold 一段时间 t,如果在 t 时间区间里用户未进行下一次点击,则浏览器会做单击跳转链接的处理,如果 t 时间里用户进行了第二次单击操作,则浏览器会禁止跳转,转而进行对该部分区域页面的缩放操作。那么这个时间区间 t 有多少呢?在 iOS Safari下,大概为 300 毫秒。这就是延迟的由来。造成的后果用户纯粹单击页面,页面需要过一段时间才响应,给用户慢体验感觉,对于 Web 开发者来说是,页面 JS 捕获 click 事件的回调函数处理,需要300ms 后才生效,也就间接导致影响其他业务逻辑的处理。
// 解决方案:
fastclick 可以解决在手机上点击事件的 300ms 延迟。
Zepto 的 touch 模块,tap 事件也是为了解决在 click 的延迟问题。

fastclick 安装与使用

参考 https://github.com/ftlabs/fastclick

fastclick 的安装

// 页面引入
<script type='application/javascript' src='/path/to/fastclick.js'></script>

// 使用npm安装
npm install fastclick

初始化FastClick实例,建议在页面的DOM文档加载完成后

//javascript 版
if ('addEventListener' in document) {
    document.addEventListener('DOMContentLoaded', function() {
        FastClick.attach(document.body);
    }, false);
}

// jQuery版
$(function() {
    FastClick.attach(document.body);
});

// 类似Common JS的模块系统方式 调用require('fastclick')会返回FastClick.attach函数。
var attachFastClick = require('fastclick');
attachFastClick(document.body);

// 使用needsclick过滤特定的元素
// 如果页面上有一些特定的元素不需要使用fastclick来立刻触发点击事件,可以在元素的class上添加needsclick:
<a class="needsclick">Ignored by FastClick</a>

26. input 获取焦点, 页面放大, 失焦后,页面未恢复

  1. 设置meta标签
<meta name="apple-mobile-web-app-capable" content="yes">  
<meta name="viewport" content="width=device-width, initial-scale=1.0,minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
  1. 将输入框的font-size属性值设为16px

为了表单能够在 iPhone 便于阅读,会将 font-size 低于 16px 的 input 元素自动缩放到 16px 的大小以防止字号不会过小而影响阅读。因此我们只需要在 CSS 中将 input 元素和 textarea 元素的字号设定为 16px 或者更大,即:

input,
textarea {
    font-size: 16px;
}

27. input 的placeholder在ios中字体显示不全

  原因可能是修改了input字体大小,但是没有修改placeholder的字体大小导致的。
  解决方法: 修改placehol的字体大小 >= input 的字体大小; 或可修改padiding值实现。
  input::-webkit-input-placeholder {
    color: #bababa;
    font-size:14px;
    padding: xxpx;
  }

28. IOS.12.2 input type="file"使用trigger(‘click’)的方式触发上传,在校信上失效的问题,微信有效。

微信使用的自带的x5webview,校信使用的是系统webview,另外,QQ扫码进入页面使用是系统webview,点击聊天内容的链接进入的用的是x5webview???

解决方法: 改为display: block; opacity: 0这种写法,而不是用js去触发点击。

29. IOS webview禁止识别手机号,邮箱等

解决办法: 配置meta

  <meta name="format-detection" content="telephone=no,date=no,address=no,email=no,url=no" />

30. 有些手机上传的图片会被旋转90度

解决办法: 可以尝试用exif.js来解决

已在工具中提供方法,引入rotateImg即可,rotateImg方法有两个参数,file:上传的图片 cb:生成正确图片之后的回调 参数为图片的blob和name

31. ISO webview中调用Geolocation API,可能导致https环境无法加http图片

IOS系统的webview还有navigator.geolocation.getCurrentPosition在非完全https站点(网站有http请求的图片)失效的问题。

参考链接:
WebKit on iOS ignores trigger(‘click’) on file input

解决办法:

首先,由于H5服务这套业务逻辑,是不可以然让所有的业务服务器支持https的,因为有的服务是客户自己定制的。

所以只有在H5服务上用nginx做图片代理, 即业务访问的图片http://b.com/zbpb/api/getfile.do?path=duty/image/reduce/a.jpeg可以通过https://h5.lezhiyun.com/image-proxy?url=http://b.com/zbpb/api/getfile.do?path=duty/image/reduce/a.jpeg来访问。

所以只有在H5服务上用nginx做图片代理, 即业务访问的图片http://b.com/zbpb/api/getfile.do?path=duty/image/reduce/a.jpeg可以通过https://h5.com/image-proxy?url=http://b.com/zbpb/api/getfile.do?path=duty/image/reduce/a.jpeg来访问。

```shell
location ~/image-proxy {
    if ($query_string ~* ^(.*)url=(.*)$){
        set $pic_url $2;
        proxy_pass $pic_url;
    }
}
```

目前已经支持这种解决方案了eg

32. ios WKWebView之视频无法播放

ios WKWebView之视频无法播放

ios视频不自动全屏播放处理, 给video同时加上 webkit-playsinline和playsinline就好了,前者针对I0S9,后者针对IOS10和11

加了webkit-playsinline,ios9.2.3可以不全屏,但是IOS11还是会自动全屏

解决办法:使用模版项目提供的视频播放控件。

33. position:fixed没定锁定位置的时候,可能原因

元素会被移出正常文档流,并不为元素预留空间,而是通过指定元素相对于屏幕视口(viewport)的位置来指定元素位置。元素的位置在屏幕滚动时不会改变。打印时,元素会出现在的每页的固定位置。fixed 属性会创建新的层叠上下文。当元素祖先的 transform, perspective 或 filter 属性非 none 时,容器由视口改为该祖先。

MDN解释

34. Prefetch

<link rel="prefetch"> 是一种 resource hint,用来告诉浏览器在页面加载完成后,利用空闲时间提前获取用户未来可能会访问的内容。

默认情况下,一个 Vue CLI 应用会为所有作为 async chunk 生成的 JavaScript 文件 (通过动态 import() 按需 code splitting 的产物) 自动生成 prefetch 提示。

这些提示会被 @vue/preload-webpack-plugin 注入,并且可以通过 chainWebpackconfig.plugin('prefetch') 进行修改和删除。

示例:

// vue.config.js
module.exports = {
  chainWebpack: config => {
    // 移除 prefetch 插件
    config.plugins.delete('prefetch')

    // 或者
    // 修改它的选项:
    config.plugin('prefetch').tap(options => {
      options[0].fileBlacklist = options[0].fileBlacklist || []
      options[0].fileBlacklist.push(/myasyncRoute(.)+?\.js$/)
      return options
    })
  }
}

当 prefetch 插件被禁用时,你可以通过 webpack 的内联注释手动选定要提前获取的代码区块:

import(/* webpackPrefetch: true */ './someAsyncComponent.vue')

webpack 的运行时会在父级区块被加载之后注入 prefetch 链接。

Prefetch 链接将会消耗带宽。如果你的应用很大且有很多 async chunk,而用户主要使用的是对带宽较敏感的移动端,那么你可能需要关掉 prefetch 链接并手动选择要提前获取的代码区块。