常见的移动端H5页面开发遇到的坑和解决办法
手机共通问题
问题一:用同等比例的图片在PC机上很清楚,但是手机上很模糊,原因是什么呢?
经研究发现是devicePixelRatio作怪,因为手机分辨率太小,如果按照分辨率来显示网页字会非常小,所以苹果就把iPhone 4的960640分辨率在网页里只显示了480320,这样devicePixelRatio=2;现在android比较乱,有1.5/2/3等,想让图片在手机里显示更为清晰必须使用2x的背景图来代替img标签(一般情况都是用2倍),例如一个div的宽高是100100,背景图必须得200200,然后background-size:contain;,这样显示出来的图片就比较清晰了;代码如下:
background:url(../images/icon/all.png) no-repeat center center;
-webkit-background-size:50px 50px;
background-size: 50px 50px;
display:inline-block;
width:100%;
height:50px;
问题二:防止手机中网页放大和缩小
这点是手机站开发者都应该知道的,就是设置meta中的viewport;有些手机站有如下声明:
<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.0//EN " "http://www.wapforum.org/DTD/xhtml-mobile10.dtd ">
设置DTD的方式是XHTML的写法,假如页面运用的是h5可以不用设置DTD,直接声明
使用viewport使页面禁止缩放,通常把user-scalable设置为0来关闭用户对页面视图缩放的行为
<meta name="viewport " content="user-scalable=0 " />
为了更好的兼容,我们使用完整的viewport设置
<meta name="viewport " content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0 " />
问题三:如何设置Web应用以全屏模式运行
apple-mobile-web-app-capable是设置Web应用是否以全屏模式运行;语法:
<meta name="apple-mobile-web-app-capable " content="yes "> //content设置为yesWeb应用会以全屏模式运行,反之则不会;content的默认值是no,表示正常显示,可以通过只读属性window.navigator.standalone来确定网页是否以全屏模式显示
问题四:如何启动或禁用自动识别页面中的电话号码
html5提供了自动调用拨号的标签,只要在a标签的href中添加tel:就可以了
<a href="tel:10010 ">10010</a>
format-detection可以启动或禁用自动识别页面中的电话号码;语法:
<meta name="format-detection " content="telephone=no "> //默认情况下设备会自动识别任何可能是电话号码的字符串,设置telephone=no可以禁用这项功能,设置不识别邮箱和地址也同理
问题五:h5网站input设置为type=number的问题
h5网页input的type设置为number一般会产生三个问题:
问题1:maxlength属性不好用
解决,我目前用的是js
<input type="number " oninput="checkTextLength(this ,10) ">
<script type="text/javascript ">
function checkTextLength(obj, length) {
if(obj.value.length > length) {
obj.value = obj.value.substr(0, length);
}
}
</script>
问题2:form提交的时候默认取整
因为form提交默认做了表单验证,step默认是1,要设置step属性,假如保留2位小数,写法如下:
<input type="number " step="0.01 " /> //input中type=number一般会自动生成一个上下箭头,点击上箭头默认增加一个step,点击下箭头默认会减少一个step;number中默认step是1,也就是step=0.01可以允许输入2位小数,并且点击上下箭头分别增加0.01和减少0.01;step和min一起使用时数值必须在min和max之间
问题3:部分安卓手机出现样式问题
去除input中这些默认样式:
input[type=number] {
-moz-appearance:textfield;
}
input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{
-webkit-appearance: none;
margin: 0;
}
去除input默认样式的方法:
input,textarea {
border: 0;
-webkit-appearance: none; //可同时屏蔽输入框怪异的内阴影,解决iOS下无法修改按钮样式,测试还发现,加了此属性后,iOS下默认还是有圆角的,不过可以用border-radius属性修改
}
问题六:select下拉选择设置问题
问题1:右对齐实现
设置如下属性
select option {
direction: rtl;
}
问题2:唤起select的option展开
zepto方式:
$(sltElement).trrgger("mousedown ");
原生js方式:
function showDropdown(sltElement) {
var event;
event = document.createEvent('MouseEvents');
event.initMouseEvent('mousedown', true, true, window);
sltElement.dispatchEvent(event);
};
问题3:禁用select默认箭头
::-ms-expand修改表单控件下拉箭头,设置隐藏并使用背景图片来修饰
select::-ms-expand { display:none; }
问题4:使用appearance改变webkit浏览器的默认外观
input,select { -webkit-appearance:none; appearance: none; }
问题七:移动端click事件延迟的问题
移动端的点击事件都会有300ms延迟,是因为浏览器在等待你是否执行双击,但此延迟导致用户体验不好,解决这个问题,我们的方案如下:
1.尽量都使用touch事件来替换click事件,例如用touchend事件(推荐)
2.用preventDefault阻止a标签的click
3.用script标签引入fastclick库去除延迟,实验证明fastclick比tap要快
4.zepto的touch模块,tap事件也是可以解决在click的延迟问题
5.延迟一定的时间(300ms+)来处理事件(不推荐)
6.以上一般都能解决,实在不行就换成click事件
7.触摸事件的响应顺序为touchstart-->touchmove-->touchend-->click,也可以通过绑定ontouchstart事件,加快对事件的响应,解决300ms延迟问题
8.若移动设备兼容性正常的话(IE/Firefox/Safari(IOS 9.3)及以上)只需加上下面meta标签即可把viewport设置成设备的实际像素,就不会有300ms的延迟
<meta name="viewport " content="width=device-width ">
click事件的延迟会导致移动端点透问题
案例如下:
<div id="haorooms ">事件测试</div>
<a href="# ">www.xxx.com</a>
div是绝对定位的蒙层且z-index高于a,我们给div绑定tap事件:
$('#haorooms').on('tap',function(){
$('#haorooms').hide();
});
我们点击蒙层时div正常消失,但是当我们在a标签上点击蒙层时,发现a链接被触发,这就是所谓的点透事件
原因:touchstart早于touchend早于click,即click的触发是有300ms左右延迟的,也就是说tap触发之后蒙层隐藏click没有触发,300ms之后由于蒙层消失click触发到了下面的a链接上;解决方案同上面的click事件延迟
问题八:移动端HTML5 audio autoplay失效问题
由于自动播放网页中的音频或视频会给用户带来困扰或不必要的流量消耗,所以苹果系统和安卓系统通常都会禁止自动播放和使用JS的触发播放,必须由用户来触发才播放;解决方法思路:先通过用户touchstart触碰触发播放并暂停(让音频开始加载),后面用JS再操作就没问题了;解决代码:
document.addEventListener('touchstart', function () {
document.getElementsByTagName('audio')[0].play();
document.getElementsByTagName('audio')[0].pause();
});
问题九:移动端样式兼容处理
当今的手机端,屏幕分辨率各有不同,为了让页面可以兼容各款手机,解决方案如下:
1.设置meta标签viewport属性,使其无视设备的真实分辨率,直接通过dpi在物理尺寸和浏览器之间重设分辨率,从而达到能有统一的分辨率的效果,并且禁止掉用户缩放
<meta name="viewport " content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no " />
2.使用rem进行屏幕适配,设置好root元素的font-size大小,然后在开发的时候所有与像素有关的布局统一换成rem单位;针对不同的手机使用媒体查询对root元素font-size进行调整
问题十:CSS动画页面闪白,动画卡顿,图片错乱的问题
解决方法:
1.尽可能地使用合成属性transform和opacity来设计CSS3动画,不使用position的left和top来定位
2.开启硬件加速
-webkit-transform: translate3d(0, 0, 0);
-moz-transform: translate3d(0, 0, 0);
-ms-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0); //可以触发硬件加速,从而让浏览器在渲染动画时从CPU转向GPU
目前像Chrome/Filefox/Safari/IE9+以及最新版本Opera都支持硬件加速,当检测到某个DOM元素应用了某些CSS规则时就会自动开启,从而解决页面闪白,保证动画流畅
3.各种应用的webview(例如微信)在遇到有大量图片时会出现img和background-image互相错乱的情况,6和6plus更为严重,目前暂时的解决方法也是动态给所有用到图片的元素加上-webkit-transform:translate3d(0,0,0)
4.页面中的滑动刷新在某些手机中出现卡顿滑不动的情况,以下给出可行的解决方案:
a.关闭probeType属性(传说是因为这个启用监听滚动状态的很耗性能,关闭这个属性滑动就会流畅很多)
document.addEventListener('touchmove', function (e) { e.preventDefault(); }, false);
b.给scroll元素增加css样式:-webkit-transform:translate3d(0,0,0);
问题十一:浮动子元素撑开父元素盒子高度
解决方法如下:
1.父元素设置为 overflow: hidden;
2.父元素设置为 display: inline-block;
等
这里两种方法都是通过设置css属性将浮动元素的父元素变成BFC(块级格式化上下文)元素,使子元素高度可以撑开父元素;不过最好使用方法1,因为inline-block元素本身会自带一些宽高度撑开其本身
BFC产生的条件:
1.html根元素
2.float的值不为none
3.display的值为inline-block/table-cell/table-caption
4.position的值为absolute或fix
5.overflow的值不为visible
BFC约束规则:
1.生成BFC元素的子元素会一个接一个的放置;垂直方向上他们的起点是一个包含块的顶部,俩个相邻子元素之间垂直距离取决于元素margin特性,在BFC中相邻的块级元素外边距会折叠
2.生成BFC元素的子元素中每个子元素的外边距和包含块的左边界相接触(对于从右到左的格式化,右外边距和右边界相接触),除非这个子元素也创建一个新的BFC(如它自身也是一个浮动元素)
3.BFC的区域不会与float的元素区域重叠
4.计算BFC高度时浮动元素也参与计算
5.BFC就是页面上一个隔离的独立容器,容器里面的子元素不会影响到外面元素,反之亦然
我们在写css常见的一些问题都可以由上面两条推出,例如:
1.Block元素与父元素同宽,所以Block元素竖直方向上垂直排列。
2.竖直方向上有的Block元素margin会重叠,水平方向不会。
3.浮动元素会尽量接近左上方或右上方。
4.为父元素设置overflow:hidden或浮动父元素,则父元素会包含其浮动的子元素。
BFC有很多实际的用处,例如防止相邻block的竖直margin重叠(塌陷)
问题十二:往返缓存问题
点击浏览器的回退有时候不会自动执行js,特别是在mobilesafari中;这与往返缓存(bfcache)有关系,解决方法:
window.onunload = function(){};
问题十三:定位的坑
1.fixed定位
ios下fixed元素容易定位出错,软键盘弹出时影响fixed元素定位,而android下不会;ios4下不支持position:fixed
解决方案:使用[Iscroll],如:
<div id="wrapper ">
<ul>
<li></li>
.....
</ul>
</div>
<script src="iscroll.js "></script>
<script>
var myscroll;
function loaded(){
myscroll=new iScroll("wrapper ");
}
window.addEventListener("DOMContentLoaded ",loaded,false);
</script>
2.position定位
Android下弹出软键盘弹出时影响absolute元素定位;解决方案如下:
var ua = navigator.userAgent.indexOf('Android');
if(ua>-1){
$('.ipt').on('focus', function(){
$('.css').css({'visibility':'hidden'})
}).on('blur', function(){
$('.css').css({'visibility':'visible'})
})
}
3.安卓手机端软键盘弹出顶起页面布局
BODY被顶起的解决办法:
$('body').height($('body')[0].clientHeight);
问题十四:audio元素和video元素在ios和andriod中播放问题
问题1:音频/视频写法
<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>
问题2:ios系统手机无法自动播放音频/视频
这个是苹果系统限制默认不允许自动播放音频/视频,需要点一下触发play()事件才能播放;那么我们可以在页面onload后触发播放事件:
document.getElementById('music').play();
到这里一般都可以播放音乐了,如果还不行很有可能是微信的限制
问题3:微信的限制
如果是微信的限制,这时需要调用微信接口,页面先引入:
<script src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js "></script>
然后JS写入微信事件:
document.addEventListener("WeixinJSBridgeReady ", function() {
document.getElementById('music').play();
}, false);
小结
1.audio元素的autoplay属性在IOS及Android上无法使用,在PC端正常
2.audio元素没有设置controls时,在IOS及Android会占据空间大小,而在PC端Chrome是不会占据任何空间
问题4:Safari浏览器自动播放
document.addEventListener('touchstart', function(){
audio.play();
}, false);
问题5:ios系统不支持动画暂停样式(animation-play-state)
H5页面一般都会有BGM,也会提供一个旋转的音乐图标供用户开启关闭音乐;我们希望当用户点击音乐按钮时图标停止旋转,再点图标顺着之前停止的位置继续跑动画;animation-play-state是最简便的方式,然而ios不支持
目前的解决方案是:音乐图标负责跑动画,图标父级元素负责记录停止时的转动值
问题6:ios系统摇一摇播放音效事件无效
在实现摇晃(引用了封装好的shake.js)手机触发某一音效这个需求时,发现在微信中音效没有被触发;后面找到原因:在ios里并没有把自定义摇晃事件shake当成交互动作,而要播放音效需要用户有交互动作;没有交互音效就没被加载,那么我们先加载音效,结合上面的微信接口:
document.addEventListener("WeixinJSBridgeReady ", function () {
shakeMusic.load();
}, false);
load()过之后再调用play()即可听到音效
问题十五:防止长按页面元素被选中
解决:加入样式可禁止用户进行复制,ios和一般的安卓都可以解决,唯独小米自带浏览器还有问题
-webkit-touch-callout:none; //系统默认菜单被禁用;可以实现页面因为长按弹出各种操作窗口
-webkit-user-select:none; //webkit浏览器
-khtml-user-select:none; //早期浏览器
-moz-user-select:none; //火狐
-ms-user-select:none; //IE10
user-select:none;
添加完这段代码后在IOS上会有问题,这时发现input框无法正在输入内容了;造成这个原因是-webkit-user-select:none;
这个属性,解决方法就是在css文件中同时设置一下input的属性,如下:
input {
-webkit-user-select:auto; //webkit浏览器
}
问题十六:html5碰到上下拉动滚动条时卡顿/慢怎么解决
body {
-webkit-overflow-scrolling: touch;
overflow-scrolling: touch;
}
overflow-x:auto在iOS有兼容问题,解决方法:
-webkit-overflow-scrolling: touch;
问题十七:点击元素产生背景或边框怎么去掉
ios用户点击一个链接会出现一个半透明灰色遮罩,如果想要禁用可设置-webkit-tap-highlight-color的alpha值为0去除灰色半透明遮罩
android用户点击一个链接会出现一个边框或者半透明灰色遮罩,不同生产商定义出来效果不一样,可设置-webkit-tap-highlight-color的alpha值为0去除部分机器自带的效果
winphone系统点击标签产生的灰色半透明背景能通过设置去掉
特殊说明:有些机型去除不了,如小米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有个副作用,就是输入法不再能够输入多个字符
}
或
a,button,input,textarea{
-webkit-tap-highlight-color: rgba(0,0,0,0);
}
在winphone下使用如下代码
<meta name="msapplication-tap-highlight " content="no ">
问题十八:浏览器后退不刷新
这种情况是以前遇到的,这里也说下;主要会发生在webview里多一点,当点击后退时页面以缓存形式出现,而不是刷新后的,很多情况下这不是你预期的效果,解决方法是用js:
window.onpageshow = function(evt){
if(evt.persisted){
document.body.style.display ="none ";
location.reload();
}
};
onpageshow每次页面加载都会触发,无论是从缓存中加载还是正常加载,这是他和onload的区别;persisted判断页面是否从缓存中读出
问题十九:部分机型存在type为search的input自带close按钮样式修改方法
有些机型的搜索input控件会自带close按钮(一个伪元素),而通常为了兼容所有浏览器我们会自己实现一个,此时去掉原生close按钮的方法为
#Search::-webkit-search-cancel-button{
display: none;
}
如果想使用原生close按钮又想使其符合设计风格,可以对这个伪元素的样式进行修改
问题二十:input的placeholder文本位置偏上的情况
input的placeholder会出现文本位置偏上的情况:PC端设置line-height等于height能够对齐,而移动端仍然是偏上,解决方案时是设置css line-height:normal;
问题二十一:transition清除闪屏
-webkit-transform-style: preserve-3d; //设置内嵌的元素在 3D 空间如何呈现:保留3D
-webkit-backface-visibility:hidden; //设置进行转换的元素的背面在面对用户时是否可见:隐藏
-webkit-perspective: 1000;
问题二十二:顶部状态栏背景色
<meta name="apple-mobile-web-app-status-bar-style " content="black " />
说明:除非你先使用apple-mobile-web-app-capable指定全屏模式,否则这个meta标签不会起任何作用;如果content设置为default,则状态栏正常显示;如果设置为blank,则状态栏会有一个黑色的背景;如果设置为blank-translucent,则状态栏显示为黑色半透明;如果设置为default或blank,则页面显示在状态栏的下方,即状态栏占据上方部分;页面占据下方部分,二者没有遮挡对方或被遮挡;如果设置为blank-translucent,则页面会充满屏幕,其中页面顶部会被状态栏遮盖住(会覆盖页面20px高度,而iphone4和itouch4的Retina屏幕为40px);默认值是default。
IOS问题
问题一:IOS中对input键盘事件keyup/keydown/keypress等支持不好的问题
用input search做模糊搜索的时候,在键盘里输入关键词,会通过ajax后台查询然后返回数据;用input监听键盘keyup事件,在安卓手机浏览器中是可以的,但是在ios手机浏览器中很慢,用输入法输入后并未立刻执行相应的keyup事件,只有删除之后才能响应;经查发现,IOS的输入法(不管是第三方还是自带)能检测到英文或数字的keyup,但检测不到中文的keyup,在输入中文后需要点回退键才开始搜索;解决办法是用html5的oninput事件去代替keyup,通过如下代码达到类似keyup的效果;oninput是HTML5的标准事件,对检测textarea,input:text,input:password和input:search这几个元素的内容修改后立即被触发,不像onchange事件要失去焦点才触发;但oninput事件在IE9以下版本不支持,需要用IE特有的onpropertychange事件替代,这个事件在用户界面改变或者使用脚本直接修改内容两种情况下都会触发,有以下几种情况:
1.修改了input:checkbox或input:radio元素的选择中状态,checked属性发生变化
2.修改了input:text或textarea元素的值,value属性发生变化
3.修改了select元素的选中项,selectedIndex属性发生变化
<input type="text " id="testInput ">
<script type="text/javascript ">
document.getElementById('testInput').addEventListener('input', function(e){
var value = e.target.value; //e.target指向事件执行时鼠标所点击区域的那个元素;初学者会认为当前事件所绑定的元素就是鼠标所点击的那个元素,这时就要看看时间绑定的元素内部有没有子元素,如果有e.target指向这个子元素,如果没有e.target和this都指向事件所绑定的元素
});
</script>
问题二:IOS键盘字母输入,默认首字母大写的解决方案
设置如下属性
<input autocapitalize="off " autocorrect="off " /> //input的三个属性autocomplete:默认为on,代表是否让浏览器自动记录输入的值,可以在input中加入autocomplete="off "来关闭记录,保密输入内容;autocapitalize:自动大小写;autocorrect:纠错
问题三:关于iOS与OS X端字体的优化(横竖屏会出现字体加粗不一致等)问题
iOS浏览器横屏时会重置字体大小,设置text-size-adjust为none可以解决iOS上的问题,但桌面版Safari的字体缩放功能会失效,因此最佳方案是将text-size-adjust为100%
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
text-size-adjust: 100%;
问题四:iOS系统中,中文输入法输入英文时,字母之间可能会出现一个六分之一空格的问题
可以通过正则去掉
this.value = this.value.replace(/\u2006/g, '');
问题五:某些情况下非可点击元素如(label,span)监听click事件,ios下不会触发
针对此种情况只需对不触发click事件的元素添加一行css代码即可
cursor: pointer;
问题六:ios对时间date()的支持不一样
var date =new Date("2016-05-31 00:00:00 ");
这种写法在安卓和pc上都正常的,唯独在ios手机上会显示NAN,调试发现,ios上只支持格式:
var date =new Date("2016/05/31 ");
调试发现2016/05/31等同2016-05-31 00:00:00,也就是说ios默认就是从0开始计算的,我们不需要设置后面的时分秒为00:00:00
问题七:iOS(safari)标签绑定点击事件无效
iOS(safari)有时候某个标签绑定点击事件无效,加上空的onclick=" "就好了,如:<a onclick=" "></a>
Android问题
问题一:flex盒模型
1.display:flex;
最新写法:display:flex;
;酷派,三星等安卓手机需加上display:-webkit-box;
兼容,否则子元素中flex:1
无法撑开宽度
2.flex-wrap:wrap;
三星手机中flex盒模型的子元素必须用display:inline-block;
;如果是block则三星手机不会换行,如果是inline元素(比如)则宽度不会撑开仍然表现为内联元素
3.flex-direction: column;
三星手机不支持,无法使用margin-top:auto
使子元素自动在最下
4.flex元素中嵌套flex
三星手机出错,必须父元素为flex,而其它祖先元素为block
问题二:text-indent和box-sizing
部分安卓机中使用text-indent属性会使元素宽度超过100%,加上box-sizing:border-box;修复正常
微信问题
问题一:微信二维码问题
1.同一个页面里要是有两个二维码,长按扫描总是只能扫出左侧/第一个二维码
解决:可视区域内只能出现一个二维码
2.使用meta标签缩放页面后长按二维码图片无反应
解决:使用以下代码后就能长按识别二维码了~
//同一张二维码图片
<img style="right:0; top:0; height: auto;width: 100%;opacity: 0;position: absolute; " src="二维码图片地址 "> //这张opacity为0隐藏起来,但实际存在且宽为100%,屏幕有多大就多大
<img src="二维码图片地址 " title="qrcode " alt="qrcode "> //这张是呈现给用户看的
二维码图片不要写为背景,不然长按没办法触发扫描功能,应使用img标签引入;有时扫描二维码后会跳转至某个地址,不幸的话QQ或者微信会对这个地址进行温馨提醒,这样会阻止部分用户继续访问,从而无法很好的将用户引导到活动想要推广的产品/品牌页面,如App的下载页面等,因此二维码的扫描测试不能少;举例:如果二维码扫描结果是应用的下载地址的,可以使用应用宝的微下载地址生成二维码,这就不会被"温馨提醒 "了
h5网站input设置为type=number,有个不需要js的解决方案:<input type="text" maxlength="10" pattern="\d*">
解决移动端键盘遮挡表单
window.addEventListener('resize', function() { if( document.activeElement.tagName === 'INPUT' || document.activeElement.tagName === 'TEXTAREA' || document.activeElement.getAttribute('contenteditable') == 'true' ) { window.setTimeout(function() { if('scrollIntoView' in document.activeElement) { document.activeElement.scrollIntoView(); } else { document.activeElement.scrollIntoViewIfNeeded(); } }, 0); } });