移动端必备的H5问题及解决方案

1px问题

响应式布局

iOS 滑动不流畅

表现

上下滑动页面会产生卡顿,手指离开页面,页面立即停止运动。整体表现就是滑动不流畅,没有滑动惯性。

产生原因

为什么 iOS 的 webview 中 滑动不流畅,它是如何定义的?

最终我在 safari 文档里面寻找到了答案(文档链接在参考资料项)。

原来在 iOS 5.0 以及之后的版本,滑动有定义有两个值 autotouch,默认值为 auto

-webkit-overflow-scrolling: touch; /* 当手指从触摸屏上移开,会保持一段时间的滚动 */

-webkit-overflow-scrolling: auto; /* 当手指从触摸屏上移开,滚动会立即停止 */

解决方案

1.在滚动容器上增加滚动 touch 方法

-webkit-overflow-scrolling 值设置为 touch

.wrapper {
    -webkit-overflow-scrolling: touch;
}

设置滚动条隐藏: .container ::-webkit-scrollbar {display: none;}

可能会导致使用position:fixed; 固定定位的元素,随着页面一起滚动

2.设置 overflow

设置外部 overflowhidden,设置内容元素 overflowauto。内部元素超出 body 即产生滚动,超出的部分 body 隐藏。

body {
    overflow-y: hidden;
}
.wrapper {
    overflow-y: auto;
}

两者结合使用更佳!

iOS 上拉边界下拉出现白色空白

表现

手指按住屏幕下拉,屏幕顶部会多出一块白色区域。手指按住屏幕上拉,底部多出一块白色区域。

产生原因

在 iOS 中,手指按住屏幕上下拖动,会触发 touchmove 事件。这个事件触发的对象是整个 webview 容器,容器自然会被拖动,剩下的部分会成空白。

解决方案

1. 监听事件禁止滑动

移动端触摸事件有三个,分别定义为

1. touchstart :手指放在一个DOM元素上。
2. touchmove :手指拖曳一个DOM元素。
3. touchend :手指从一个DOM元素上移开。

显然我们需要控制的是 touchmove 事件,由此我在 W3C 文档中找到了这样一段话

Note that the rate at which the user agent sends touchmove events is implementation-defined, and may depend on hardware capabilities and other implementation details.

If the preventDefault method is called on the first touchmove event of an active touch point, it should prevent any default action caused by any touchmove event associated with the same active touch point, such as scrolling.

touchmove 事件的速度是可以实现定义的,取决于硬件性能和其他实现细节

preventDefault 方法,阻止同一触点上所有默认行为,比如滚动。

由此我们找到解决方案,通过监听 touchmove,让需要滑动的地方滑动,不需要滑动的地方禁止滑动。

值得注意的是我们要过滤掉具有滚动容器的元素。

实现如下:

document.body.addEventListener('touchmove', function(e) {
    if(e._isScroller) return;
    // 阻止默认事件
    e.preventDefault();
}, {
    passive: false
});

2. 滚动妥协填充空白,装饰成其他功能

在很多时候,我们可以不去解决这个问题,换一直思路。根据场景,我们可以将下拉作为一个功能性的操作

比如: 下拉后刷新页面

页面放大或缩小不确定性行为

表现

双击或者双指张开手指页面元素,页面会放大或缩小。

产生原因

HTML 本身会产生放大或缩小的行为,比如在 PC 浏览器上,可以自由控制页面的放大缩小。但是在移动端,我们是不需要这个行为的。所以,我们需要禁止该不确定性行为,来提升用户体验。

原理与解决方案

HTML meta 元标签标准中有个 中 viewport 属性,用来控制页面的缩放,一般用于移动端。如下图 MDN 中介绍

移动端常规写法

<meta name="viewport" content="width=device-width, initial-scale=1.0">

因此我们可以设置 maximum-scaleminimum-scaleuser-scalable=no 用来避免这个问题

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

click 点击事件延时与穿透

表现

监听元素 click 事件,点击元素触发时间延迟约 300ms

点击蒙层,蒙层消失后,下层元素点击触发。

产生原因

为什么会产生 click 延时?

iOS 中的 safari,为了实现双击缩放操作,在单击 300ms 之后,如果未进行第二次点击,则执行 click 单击操作。也就是说来判断用户行为是否为双击产生的。但是,在 App 中,无论是否需要双击缩放这种行为,click 单击都会产生 300ms 延迟。

为什么会产生 click 点击穿透?

双层元素叠加时,在上层元素上绑定 touch 事件,下层元素绑定 click 事件。由于 click 发生在 touch 之后,点击上层元素,元素消失,下层元素会触发 click 事件,由此产生了点击穿透的效果。

原理与解决方案

解决方案一:使用 touchstart 替换 click

前面已经介绍了,移动设备不仅支持点击,还支持几个触摸事件。 那么我们现在基本思路就是用 touch 事件代替click 事件。

click 替换成 touchstart 不仅解决了 click 事件都延时问题,还解决了穿透问题。因为穿透问题是在 touchclick 混用时产生。

在原生中使用

el.addEventListener("touchstart", () => { console.log("ok"); }, false);

在 vue 中使用

<button @touchstart="handleTouchstart()">点击</button>

开源解决方案中,也是既提供了 click 事件,又提供了touchstart 事件。如 vant 中的 button 组件

那么,是否可以将 click 事件全部替换成 touchstart 呢?为什么开源框架还会给出 click 事件呢?

我们想象一种情景,同时需要点击和滑动的场景下。如果将 click 替换成 touchstart 会怎样?

事件触发顺序: touchstart, touchmove, touchend, click

很容易想象,在我需要touchmove滑动时候,优先触发了touchstart的点击事件,是不是已经产生了冲突呢?

所以呢,在具有滚动的情况下,还是建议使用 click 处理。

在接下来的fastclick开源库中也做了如下处理。 针对 touchstarttouchend,截取了部分源码。

// If the target element is a child of a scrollable layer (using -webkit-overflow-scrolling: touch) and:
// 1) the user does a fling scroll on the scrollable layer
// 2) the user stops the fling scroll with another tap
// then the event.target of the last 'touchend' event will be the element that was under the user's finger
// when the fling scroll was started, causing FastClick to send a click event to that layer - unless a check
// is made to ensure that a parent layer was not scrolled before sending a synthetic click (issue #42).
this.updateScrollParent(targetElement);
// Don't send a synthetic click event if the target element is contained within a parent layer that was scrolled
// and this tap is being used to stop the scrolling (usually initiated by a fling - issue #42).
scrollParent = targetElement.fastClickScrollParent;
if (scrollParent && scrollParent.fastClickLastScrollTop !== scrollParent.scrollTop) {
	return true;
}

主要目的就是,在使用 touchstart 合成 click 事件时,保证其不在滚动的父元素之下。

解决方案二: 使用 fastclick 库

使用 npm/yarn 安装后使用

import FastClick from 'fastclick';

FastClick.attach(document.body, options);

同样,使用fastclick库后,click 延时和穿透问题都没了

按照我的惯例,只要涉及开源库,那么我们一定要去了解它实现的原理。主要是将现有的原生事件集合封装合成一个兼容性较强的事件集合。

fastclick源码open in new window 核心代码不长, 1000 行不到。有兴趣可以了解一下!

软键盘将页面顶起来、收起未回落问题

表现

Android 手机中,点击 input 框时,键盘弹出,将页面顶起来,导致页面样式错乱。

移开焦点时,键盘收起,键盘区域空白,未回落。

产生原因

我们在app 布局中会有个固定的底部。安卓一些版本中,输入弹窗出来,会将解压 absolutefixed 定位的元素。导致可视区域变小,布局错乱。

原理与解决方案

软键盘将页面顶起来的解决方案,主要是通过监听页面高度变化,强制恢复成弹出前的高度。

// 记录原有的视口高度
const originalHeight = document.body.clientHeight || document.documentElement.clientHeight;

window.onresize = function(){
  var resizeHeight = document.documentElement.clientHeight || document.body.clientHeight;
  if(resizeHeight < originalHeight ){
    // 恢复内容区域高度
    // const container = document.getElementById("container")
    // 例如 container.style.height = originalHeight;
  }
}

键盘不能回落问题出现在 iOS 12+ 和 wechat 6.7.4+ 中,而在微信 H5 开发中是比较常见的 Bug。

兼容原理,1.判断版本类型 2.更改滚动的可视区域

const isWechat = window.navigator.userAgent.match(/MicroMessenger\/([\d\.]+)/i);
if (!isWechat) return;
const wechatVersion = wechatInfo[1];
const version = (navigator.appVersion).match(/OS (\d+)_(\d+)_?(\d+)?/);

 // 如果设备类型为iOS 12+ 和wechat 6.7.4+,恢复成原来的视口
if (+wechatVersion.replace(/\./g, '') >= 674 && +version[1] >= 12) {
  window.scrollTo(0, Math.max(document.body.clientHeight, document.documentElement.clientHeight));
}

window.scrollTo(x-coord, y-coord),其中window.scrollTo(0, clientHeight)恢复成原来的视口

iPhone X系列安全区域适配问题

表现

头部刘海两侧区域或者底部区域,出现刘海遮挡文字,或者呈现黑底或白底空白区域。

产生原因

iPhone X 以及它以上的系列,都采用刘海屏设计全面屏手势。头部、底部、侧边都需要做特殊处理。才能适配 iPhone X 的特殊情况。

解决方案

设置安全区域,填充危险区域,危险区域不做操作和内容展示。

危险区域指头部不规则区域,底部横条区域,左右触发区域。

具体操作为:viewport-fit meta 标签设置为 cover,获取所有区域填充。 判断设备是否属于 iPhone X,给头部底部增加适配层

viewport-fit 有 3 个值分别为:

  • auto:此值不影响初始布局视图端口,并且整个web页面都是可查看的。
  • contain

视图端口按比例缩放,以适合显示内嵌的最大矩形。

  • cover:视图端口被缩放以填充设备显示。强烈建议使用 safe area inset 变量,以确保重要内容不会出现在显示之外。

设置 viewport-fit 为 cover

<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes, viewport-fit=cover">

增加适配层

使用 safe area inset 变量

/* 适配 iPhone X 顶部填充*/
@supports (top: env(safe-area-inset-top)){
  body,
  .header{
      padding-top: constant(safe-area-inset-top, 40px);
      padding-top: env(safe-area-inset-top, 40px);
      padding-top: var(safe-area-inset-top, 40px);
  }
}
/* 判断iPhoneX 将 footer 的 padding-bottom 填充到最底部 */
@supports (bottom: env(safe-area-inset-bottom)){
    body,
    .footer{
        padding-bottom: constant(safe-area-inset-bottom, 20px);
        padding-bottom: env(safe-area-inset-bottom, 20px);
        padding-top: var(safe-area-inset-bottom, 20px);
    }
}

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

safe-area-inset-*由四个定义了视口边缘内矩形的 top, right, bottomleft 的环境变量组成,这样可以安全地放入内容,而不会有被非矩形的显示切断的风险。对于矩形视口,例如普通的笔记本电脑显示器,其值等于零。 对于非矩形显示器(如圆形表盘,iPhoneX 屏幕),在用户代理设置的四个值形成的矩形内,所有内容均可见。

其中 env() 用法为 env( <custom-ident> , <declaration-value>? ),第一个参数为自定义的区域,第二个为备用值。

其中 var() 用法为 var( <custom-property-name> , <declaration-value>? ),作用是在 env() 不生效的情况下,给出一个备用值。

constant()css 2017-2018 年为草稿阶段,是否已被标准化未知。而其他iOS 浏览器版本中是否有此函数未知,作为兼容处理而添加进去。

详情请查看文章末尾的参考资料。

兼容性

页面生成为图片和二维码问题

表现

在工作中有需要将页面生成图片或者二维码的需求。可能我们第一想到的,交给后端来生成更简单。但是这样我们需要把页面代码全部传给后端,网络性能消耗太大。

解决方案

生成二维码

使用 QRCode 生成二维码

import QRCode from 'qrcode';
// 使用 async 生成图片
const options = {};
const url = window.location.href;
async url => {
  try {
    console.log(await QRCode.toDataURL(url, options))
  } catch (err) {
    console.error(err);
  }
}

await QRCode.toDataURL(url, options) 赋值给 图片 url 即可

生成图片

主要是使用 htmlToCanvas 生成 canvas 画布

import html2canvas from 'html2canvas';

html2canvas(document.body).then(function(canvas) {
    document.body.appendChild(canvas);
});

但是不单单在此处就完了,由于是 canvas 的原因。移动端生成出来的图片比较模糊。

我们使用一个新的 canvas 方法多倍生成,放入一倍容器里面,达到更加清晰的效果,通过超链接下载图片

下载文件简单实现,更完整的实现方式之后更新

const scaleSize = 2;
const newCanvas = document.createElement("canvas");
const target = document.querySelector('div');
const width = parseInt(window.getComputedStyle(target).width);
const height = parseInt(window.getComputedStyle(target).height);
newCanvas.width = width * scaleSize;
newCanvas.height = widthh * scaleSize;
newCanvas.style.width = width + "px";
newCanvas.style.height =width + "px";
const context = newCanvas.getContext("2d");
context.scale(scaleSize, scaleSize);
html2canvas(document.querySelector('.demo'), { canvas: newCanvas }).then(function(canvas) {
  // 简单的通过超链接设置下载功能
  document.querySelector(".btn").setAttribute('href', canvas.toDataURL());
}

根据需要设置 scaleSize 大小

微信公众号分享问题

表现

在微信公众号 H5 开发中,页面内部点击分享按钮调用 SDK,方法不生效。

解决方案

解决方法:添加一层蒙层,做分享引导。

因为页面内部点击分享按钮无法直接调用,而分享功能需要点击右上角更多来操作。

然后用户可能不知道通过右上角小标里面的功能分享。又想引导用户分享,这时应该怎么做呢?

技术无法实现的,从产品出发。

如果技术上实现复杂,或者直接不能实现。不要强行钻牛角尖哦,学会怼产品,也是程序员必备的能力之一。

表现

使用vue的路由跳转,在ios微信配置报错,不能使用自定义分享。

解决方案

使用window.location.reload(),刷新页面成功。

问题参考open in new window

H5 调用 SDK 相关解决方案

产生原因

在 Hybrid App 中使用 H5 是最常见的不过了,刚接触的,肯定会很生疏模糊。不知道 H5 和 Hybrid 是怎么交互的。怎样同时支持 iOS 和 Android 呢?现在来谈谈 Hybrid 技术要点,原生与 H5 的通信

解决方案

使用 DSBridge 同时支持 iOS 与 Android

文档见参考资料

SDK小组 提供方法

  1. 注册方法 bridge.register
bridge.register('enterApp', function() {
  broadcast.emit('ENTER_APP')
})
  1. 回调方法 bridge.call
export const getSDKVersion = () => bridge.call('BLT.getSDKVersion')

事件监听与触发法

const broadcast = {
  on: function(name, fn, pluralable) {
    this._on(name, fn, pluralable, false)
  },
  once: function(name, fn, pluralable) {
    this._on(name, fn, pluralable, true)
  },
  _on: function(name, fn, pluralable, once) {
    let eventData = broadcast.data
    let fnObj = { fn: fn, once: once }
    if (pluralable && Object.prototype.hasOwnProperty.call(eventData, 'name')) {
      eventData[name].push(fnObj)
    } else {
      eventData[name] = [fnObj]
    }
    return this
  },
  emit: function(name, data, thisArg) {
    let fn, fnList, i, len
    thisArg = thisArg || null
    fnList = broadcast.data[name] || []
    for (i = 0, len = fnList.length; i < len; i++) {
      fn = fnList[i].fn
      fn.apply(thisArg, [data, name])
      if (fnList[i].once) {
        fnList.splice(i, 1)
        i--
        len--
      }
    }
    return this
  },
  data: {}
}
export default broadcast

踩坑注意

方法调用前,一定要判断 SDK 是否提供该方法 如果 Android 提供该方法,iOS 上调用就会出现一个方法调用失败等弹窗。 怎么解决呢?

提供一个判断是否 Android、iOS。根据设备进行判断

export const hasNativeMethod = (name) =>
  return bridge.hasNativeMethod('BYJ.' + name)
}

export const getSDKVersion = function() {
  if (hasNativeMethod('getSDKVersion')) {
    bridge.call('BYJ.getSDKVersion')
  }
}

同一功能需要iOS,Android方法名相同,这样更好处理哦

H5 调试相关方案策略

表现

调试代码一般就是为了查看数据定位 bug。分为两种场景,一种是开发和测试时调试,一种是生产环境上调试。

为什么有生产环境上调试呢?有些时候测试环境上没法复现这个 bug,测试环境和生产环境不一致,此时就需要紧急生产调试。

在 PC 端开发时,我们可以直接掉出控制台,使用浏览器提供的工具操作devtools或者查看日志。但是在 App 内部我们怎么做呢?

原理与解决方案

1. vconsole 控制台插件

使用方法也很简单

import Vconsole from 'vconsole'

new Vconsole()

有兴趣看看它实现的基本原理,我们关注的点应该在 vsconsole 如何打印出我们所有 log 的 腾讯开源vconsoleopen in new window

上述方法仅用于开发和测试。生产环境中不允许出现,所以,使用时需要对环境进行判断。

import Vconsole from 'vconsole'
if (process.env.NODE_ENV !== 'production') {
    new Vconsole()
}

2. 代理 + spy-debugger

操作稍微有点麻烦,不过我会详细写出,大致分为 4 个步骤

  1. 安装插件(全局安装)
sudo npm install spy-debugger -g
  1. 手机与电脑置于同一 wifi 下,手机设置代理

设置手机的 HTTP 代理,代理 IP 地址设置为 PC 的 IP 地址,端口为spy-debugger的启动端口

spy-debugger 默认端口:9888

Android :设置 - WLAN - 长按选中网络 - 修改网络 - 高级 - 代理设置 - 手动

IOS :设置 - Wi-Fi - 选中网络, 点击感叹号, HTTP 代理手动

  1. 手机打开浏览器或者 app 中 H5 页面

  2. 打开桌面日志网站进行调试,点击 npm 控制台监听地址。查看抓包和 H5 页面结构

这种方式可以调试生成环境的页面,不需要修改代码,可以应付大多数调试需求

参考资料

ios页面橡皮弹回效果遮挡页面选项卡

  • 有时body和html的height: 100%去除掉问题可能就没有了。

  • 到达临界值的时候在阻止事件默认行为

var startY,endY;
//记录手指触摸的起点坐标
$('body').on('touchstart',function (e) {
    startY = e.touches[0].pageY;
});
$('body').on('touchmove',function (e) {
	endY = e.touches[0].pageY;  //记录手指触摸的移动中的坐标
	//手指下滑,页面到达顶端不能继续下滑
	if(endY>startY&& $(window).scrollTop()<=0){
		e.preventDefault();
	}
//手指上滑,页面到达底部能继续上滑
	if(endY<startY&& $(window).scrollTop() + $(window).height()>=$('body')[0].scrollHeight){
		e.preventDefault();
	}
})

有时也会碰见弹窗出来后两个层的橡皮筋效果出现问题,我们可以在弹出弹出时给底层页面加上一个类名,类名禁止页面滑动这样下层的橡皮筋效果就会被禁止,就不会影响弹窗层。

ios机型margin属性无效问题

  • 设置html body的高度为百分比时,margin-bottom在safari里失效

  • 直接padding代替margin

ios绑定点击事件不执行

  • 通过添加 cursor: pointer; 使得元素变成了可点击的了

添加样式cursor :pointer。点击后消除背景闪一下的css:-webkit-tap-highlight-color:transparent

  • 将 click 事件直接绑定到目标元素(即 .target ) 上
  • 将目标元素换成<a> 或者 <button> 等可点击的元素
  • 给目标元素添加一个空的 onclick=""(<div class="target" onclick="">点击我!</div>)
  • 把 click 改成 touchend 或 touchstart(注意加上preventDefault)
  • 将 click 元素委托到非 document 或 body 的父级元素上

ios键盘换行变为搜索

  • 首先,input 要放在 form里面。

  • 这时 "换行" 已经变成 “前往”。

  • 如果想变成 “搜索”,input 设置 type="search"。

有时因为服务器或者别的原因导致页面上的图片没有找到

这是我们想需要用一个本地的图片代替没有找的的图片

<script type="text/javascript">
	function nofind(){
	var img=event.srcElement;
	img.src="images/logoError.png";
	img.onerror=null; // 控制不要一直跳动
}
</script>
<img src="images/logo.png" onerror="nofind();" />

transform属性影响position:fixed

规范中有规定:如果元素的transform值不为none,则该元素会生成包含块和层叠上下文。CSS Transforms Module Level 1不只在手机上,电脑上也一样。除了fixed元素会受影响之外,z-index(层叠上下文)值也会受影响。绝对定位元素等和包含块有关的属性都会受到影响。当然如果transform元素的display值为inline时又会有所不同。最简单的解决方法就是transform元素内部不能有absolute、fixed元素.

ios对position: fixed不太友好,有时我们需要加点处理

在安卓上面,点击页面底部的输入框,软键盘弹出,页面移动上移。

而ios上面,点击页面底部输入框,软键盘弹出,输入框看不到了。。。查资料说什么的都有,iscroll,jquery-moblie,absolute,fixe,static都非常复杂,要改很多。。。

让他弹出时让滚动条在最低部

var u = navigator.userAgent, app = navigator.appVersion;
var isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //ios终端
if (isiOS) {
    $('textarea').focus(function () {
        window.setTimeout('scrollBottom()', 500);
    });
}
function scrollBottom() {
    window.scrollTo(0, $('body').height());
}

移动开发不同手机弹出数字键盘问题

  • type="tel"

iOS和Android的键盘表现都差不多

  • type="number"

优点是Android下实现的一个真正的数字键盘

缺点一:iOS下不是九宫格键盘,输入不方便

缺点二:旧版Android(包括微信所用的X5内核)在输入框后面会有超级鸡肋的小尾巴,好在Android 4.4.4以后给去掉了。

不过对于缺点二,我们可以用webkit私有的伪元素给fix掉:

input[type=number]::-webkit-inner-spin-button,
input[type=number]::-webkit-outer-spin-button {
	-webkit-appearance: none;
	appearance: none;
	margin: 0;
}
  • pattern属性

pattern用于验证表单输入的内容,通常HTML5的type属性,比如email、tel、number、data类、url等,已经自带了简单的数据格式验证功能了,加上pattern后,前端部分的验证更加简单高效了。

显而易见,pattern的属性值要用正则表达式。

实例 简单的数字验证

数字的验证有两个:

<input type="number" pattern="d">

<input type="number" pattern="[0-9]*">

Meta基础知识

<meta name="viewport"content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no" />
<!-- width    设置viewport宽度,为一个正整数,或字符串‘device-width’ -->
<!-- height   设置viewport高度,一般设置了宽度,会自动解析出高度,可以不用设置 -->
<!-- initial-scale    默认缩放比例,为一个数字,可以带小数 -->
<!-- minimum-scale    允许用户最小缩放比例,为一个数字,可以带小数 -->
<!-- maximum-scale    允许用户最大缩放比例,为一个数字,可以带小数 -->
<!-- user-scalable    是否允许手动缩放 -->
<!-- 空白页基本meta标签 -->
<!-- 设置缩放 -->
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no, minimal-ui" />
<!-- 可隐藏地址栏,仅针对IOS的Safari(注:IOS7.0版本以后,safari上已看不到效果) -->
<meta name="apple-mobile-web-app-capable" content="yes" />
<!-- 仅针对IOS的Safari顶端状态条的样式(可选default/black/black-translucent ) -->
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<!-- IOS中禁用将数字识别为电话号码/忽略Android平台中对邮箱地址的识别 -->
<meta name="format-detection"content="telephone=no, email=no" />
<!-- 其他meta标签 -->
<!-- 启用360浏览器的极速模式(webkit) -->
<meta name="renderer" content="webkit">
<!-- 避免IE使用兼容模式 -->
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!-- 针对手持设备优化,主要是针对一些老的不识别viewport的浏览器,比如黑莓 -->
<meta name="HandheldFriendly" content="true">
<!-- 微软的老式浏览器 -->
<meta name="MobileOptimized" content="320">
<!-- uc强制竖屏 -->
<meta name="screen-orientation" content="portrait">
<!-- QQ强制竖屏 -->
<meta name="x5-orientation" content="portrait">
<!-- UC强制全屏 -->
<meta name="full-screen" content="yes">
<!-- QQ强制全屏 -->
<meta name="x5-fullscreen" content="true">
<!-- UC应用模式 -->
<meta name="browsermode" content="application">
<!-- QQ应用模式 -->
<meta name="x5-page-mode" content="app">
<!-- windows phone 点击无高光 -->
<meta name="msapplication-tap-highlight" content="no">

移动端如何定义字体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; }

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

 <!-- 一、打电话 -->
<a href="tel:0755-10086">打电话给:0755-10086</a>
  <!-- 二、发短信,winphone系统无效 -->
<a href="sms:10086">发短信给: 10086</a>
 <!-- 三、写邮件 -->
<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=<img src='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<img src='images/1.jpg' />">点击我发邮件</a>

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

  • 以下支持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

点击元素产生背景或边框怎么去掉

// ios用户点击一个链接,会出现一个半透明灰色遮罩, 如果想要禁用,可设置-webkit-tap-highlight-color的alpha值为0去除灰色半透明遮罩;
// android用户点击一个链接,会出现一个边框或者半透明灰色遮罩, 不同生产商定义出来额效果不一样,可设置-webkit-tap-highlight-color的alpha值为0去除部分机器自带的效果;
// winphone系统,点击标签产生的灰色半透明背景,能通过设置<meta name="msapplication-tap-highlight" content="no">去掉;
// 特殊说明:有些机型去除不了,如小米2。对于按钮类还有个办法,不使用a或者input标签,直接用div标签
a,button,input,textarea {
    -webkit-tap-highlight-color: rgba(0,0,0,0);
    -webkit-user-modify:read-write-plaintext-only; //-webkit-user-modify有个副作用,就是输入法不再能够输入多个字符
}
// 也可以
* { -webkit-tap-highlight-color: rgba(0,0,0,0); }
// winphone下
<meta name="msapplication-tap-highlight" content="no">

美化表单元素

  • 使用appearance改变webkit浏览器的默认外观
input, select {
	-webkit-appearance:none;
	appearance: none;
}
  • winphone下,使用伪元素改变表单元素默认外观
/* 禁用select默认箭头,::-ms-expand修改表单控件下拉箭头,设置隐藏并使用背景图片来修饰 */

select::-ms-expand {
	display: none;
}
  • 禁用radio和checkbox默认样式,::-ms-check修改表单复选框或单选框默认图标,设置隐藏并使用背景图片来修饰
input[type=radio]::-ms-check,
input[type=checkbox]::-ms-check {
	display: none;
}
  • 禁用pc端表单输入框默认清除按钮,::-ms-clear修改清除按钮,设置隐藏并使用背景图片来修饰
input[type=text]::-ms-clear,
input[type=tel]::-ms-clear,
input[type=number]::-ms-clear {
	display: none;
}

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

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

input标签添加上disable属性在ios端字体颜色不兼容的问题?

input[disabled],input:disabled,input.disabled{
  color: #3e3e3e;
  -webkit-text-fill-color: #3e3e3e;
  -webkit-opacity:1;
  opacity: 1;
}

IOS 的光标大小问题

IE:不管该行有没有文字,光标高度与font-size一致。

FF:该行有文字时,光标高度与font-size一致。该行无文字时,光标高度与input的height一致。

Chrome:该行无文字时,光标高度与line-height一致;该行有文字时,光标高度从input顶部到文字底部(这两种情况都是在有设定line-height的时候),如果没有line-height,则是与font-size一致。

IOS中情况和Chrome 相似。

设置字体大小和行高一致,然后通过 padding 撑开大小

只给IE浏览器设置 line-height

-ms-line-height:40px;

贡献者: mankueng