@fengfeng
2014-10-24T06:46:24.000000Z
字数 11975
阅读 2361
note
mobile
Position fixed & scrolling on iOS
应该是反映最多的问题.但是手机屏幕很小,对于一些要重点突出的地方,还特别需要fixed在视口的某个位置,
我遇到的问题包括:
呼出系统输入法后,fixed元素位置乱飘.
当文本框获取焦点的时候,就把元素设置为position: static; 失去焦点后再设置为fixed。
fixed的元素是后弹出的,点击发生击穿现象(会触发弹层下面元素的click)
涉及整页动画时,元素位置乱飘 如果祖先元素使用了transform相关的样式,fixed元素的不按照视口来定位.
fixed的元素有input框时在ios上的bug(可以考虑头和底部定高,中间加上一个iScroll的内容区域实现头尾固定,中间内容滑动的UI交互布局);
解决的思路
用代码,触发一下滚动(document.body.scrollTop =
xx),我用这个方法解决了iPhone某版本上(specifically Webkit 534.46 on iOS 5.1.1 as mobile Safari, and now Chrome for iOS),弹层击穿现象.如果测试的时候,出现fixed相关问题,都可以先试着手动滚动一下屏幕,看能否修复.或添加 cursor:pointer样式
用absolute元素替换.基本能解决问题,但是要多些一些代码,而且有明显的卡顿感.
现在的情况
现在的情况是,新版的手机浏览器处理fixed元素的健壮性越来越好.呼出输入法虽然还有些bug,但是比以前出现的问题要好很多,一般可以接受.除了第四条,其他问题基本都还ok.
关于第四条,把fixed元素移出去就好.如果你再body上应用transform,那么请容许我给你点根蜡烛.stackoverflow上有个相关的问题,大家可以看一下.
补充说明
有一个全屏遮罩的fixed写法,一直再用
.full-cover{
position:fixed;
top:0;left:0;right:0;bottom:0;
}
这个用过bootstrap的有心人应该都知道.但是还是遇到不少不知道的同学,在这啰嗦一下.
tap事件穿透(解决方案:click事件代替, 或者尝试fastclick这个框架);
或者尝试下面的办法重写一下zepto绑定的事件
/*************** 重写zepto on方法避免事件穿透 ******************/
(function() {
var INTERVAL_MIN = 500;
var lastCalledTime = (new Date()).getTime();
function throttle(handler) {
return function() {
var curTime = (new Date()).getTime();
//两次tap事件的间隔如果不大于500
if(curTime - lastCalledTime > INTERVAL_MIN) {
lastCalledTime = curTime;
handler.apply(this, arguments);
}
}
}
var oldOn = $.fn.on;
$.fn.on = function( evt ){
if(evt === 'tap'){
var args = Array.prototype.slice.call(arguments);
var handlerIndex;
for(var i = 0; i < args.length; i++) {
if(typeof args[i] === 'function') {
handlerIndex = i;
break;
}
}
args[handlerIndex] = throttle(args[handlerIndex]);
this.on('click', function(e) {
e.preventDefault();
});
return oldOn.apply( this, args );
}
return oldOn.apply( this, arguments );
};
})();
解决原理:正常有意义的用户操作不会在500毫秒内连续触发两次tap事件,如果发现两次tap事件的时间间隔不大于500毫秒则阻止第二次tap事件
有两个副作用和一个不能修复的问题
(1). 可能会穿透点到a链接上,需要额外给a绑定tap事件,在js中进行跳转
(2). trigger主动触发得时候可能有问题
(3).无法解决跨页面的穿透问题
通过设置a标签的href 为tel:电话号码和sms:电话号码,可以直接使用手机的打电话和发短信功能.但是这里有两个小坑.
1.安卓某些版本的webview上,tel:会报找不到页面
解决方案 修改java代码
2.发短信时,如果有预加内容,安卓和iPhone的schema时不同的,需要区别对待,主要?和;
安卓: <a href="sms:123456789?body=sometext">点击发短信</a>
//ios7下sms的body处好像有问题,无法预制发送内容.
ios:<a href="sms:123456789;body=sometext">点击发短信</a>
1.安卓下swipe*的方法很难触发
这是安卓的一个老问题了.谷歌一下 类似zepto android swipe的关键字,就能发现不少.很多项目中的issue都能找到这个问题,连安卓自身项目里都有相关issue(链接要翻墙)
解决方法就是在touchstart或touchmove事件中,主动调用e.preventDefault()
如果使用zepto的库,有两种方案,
//1.在监听函数中调用e.preventDefault()
$('#ele_id').on('swipeLeft',function(e){
e.preventDefault();
//....
})
//2.修改库的源代码,再bind touchmove事件时,添加
.on('touchmove MSPointerMove pointermove', function(e){
if((_isPointerType = isPointerEventType(e, 'move')) &&
!isPrimaryTouch(e)) return
firstTouch = _isPointerType ? e : e.touches[0]
cancelLongTap()
touch.x2 = firstTouch.pageX
touch.y2 = firstTouch.pageY
deltaX += Math.abs(touch.x1 - touch.x2)
deltaY += Math.abs(touch.y1 - touch.y2)
//只有下面两行是要修改的代码,上面的代码帮大家定位
//这里当时安卓系统,且是明显的横向滑动时,调用preventDefault
if(isAndroid && deltaX > 10 && deltaX>deltaY){
e.preventDefault()
}
})
(注:`isAndroid`变量是用来表征是不是安卓手机
var isAndroid = false;
if (navigator.userAgent.match(/Android/i)){
isAndroid =true;
}
)//end of 注
对于安卓的swipeUp和swipeDown,就不建议去做任何干涉,因为会影响浏览器本身的滚动
2.以上下滑动为主的操作,有可能触发swipeLeft/Right事件,而不是swipeUp/Down事件.这个主要是因为native scroll的一些特性,导致算距离时竖向的距离可能会很小,而上下滑的最后,一般会有一个横向滑动的连带动作,导致deltaX>deltaY,从而判断出错.
zepto中,delta在touchmove中是累加的,所以基本没啥问题.
deltaX += Math.abs(touch.x1 - touch.x2)
af.touchEvents.js中,问题很严重.我是把取坐标时的pageX/pageY改成了clientX/clientY来解决这个问题的.供大家参考
补充说明
最后说一下,还是慎用左右滑动的设计,一是兼容性问题.二是,微信等app是手机网页主要的入口,而从左向右的滑动,很容易关闭页面.
看国外的资料,因为MP3的版权问题,会让大家准备ogg等格式的文件.在天朝,版权问题吗(省略几个字)…所以直接上MP3.
<audio>
<source id="mp3source" src="yours.mp3" type="audio/mpeg">
</audio>
虽然很多资料上说,MP3格式的兼容性最好.但是这里还是有坑.当时运营同学给我一段音频,mp3格式,发现iPhone下放不了.查了很多资料,最后在一个论坛里找到,ios下MP3要满足一定条件
Try changing the MP3 to 44100Hz, 128kbs
其他参数的我没试过,但是按上面要求转换出得MP3,都可以在iPhone上使用.
这个不是 BUG,由于自动播放网页中的音频或视频,会给用户带来一些困扰或者不必要的流量消耗,所以苹果系统和安卓系统通常都会禁止自动播放和使用 JS 的触发播放,必须由用户来触发才可以播放。
解决方法思路:先通过用户 touchstart 触碰,触发播放并暂停(音频开始加载,后面用 JS 再操作就没问题了)。
解决代码:
document.addEventListener('touchstart', function () {
document.getElementsByTagName('audio')[0].play();
document.getElementsByTagName('audio')[0].pause();
});
方案出处:http://stackoverflow.com/questions/17350924/iphone-html5-audio-tag-not-working
扩展阅读:http://yujiangshui.com/recent-projects-review/#toc-7
离线缓存更新成功后必须刷新页面才能显示新的修改(写个全局的方法,监听updateready后,主动帮用户刷新一次页面);
PC端,这两个API在低版本的IE下是没有,所以是需要用try..catch包裹的.
在移动端,我刚刚开始是不加的,所测试的手机也没问题.但是现在很多浏览器有无痕模式,这个模式下,localStorage相关的API时禁用的.所以使用时,还是要保证代码的健壮性
注意input的type: 比如希望输入手机号的input,应该用type=tel(希望输入纯数字的,个人觉得type=tel也是最好的选择)
监听input 的oninput事件来代替onchange,这两个事件的含义,查一下就知道,不啰嗦了
如果input或button的有怪异的默认样式,尝试appearance:none;(-webkit-appearance:none;)
支持性有一定问题,因为浏览器会针对此类型 input 增加 datepicker 模块,看上去没那么必要支持 placeholder。
对 input type date 使用 placeholder 的目的是为了让用户更准确的输入日期格式,iOS 上会有 datepicker 不会显示 placeholder 文字,但是为了统一表单外观,往往需要显示。Android 部分机型没有 datepicker 也不会显示 placeholder 文字。
简单的进行了测试:
桌面端(Mac)
Safari 不支持 datepicker,placeholder 正常显示。
Firefox 不支持 datepicker,placeholder 正常显示。
Chrome 支持 datepicker,显示 年、月、日 格式,忽略 placeholder。
移动端
iPhone5 iOS7 有 datepicker 功能,但是不显示 placeholder。
Andorid 4.0.4 无 datepicker 功能,不显示 placeholder
问题解决方法:
先使其 type 为 text,此时支持 placeholder,当触摸或者聚焦的时候,使用 JS 切换使其触发 datepicker 功能。
要CSS伪类 :active 生效,只需要给 document 绑定 touchstart 或 touchend 事件
<style>
a {
color: #000;
}
a:active {
color: #fff;
}
</style>
<a herf=foo >bar</a>
<script>
document.addEventListener('touchstart',function(){},false);
</script>
-webkit-transform-style: preserve-3d;
/*设置内嵌的元素在 3D 空间如何呈现:保留 3D*/
-webkit-backface-visibility: hidden;
/*(设置进行转换的元素的背面在面对用户时是否可见:隐藏)*/
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%;
click 事件普遍 300ms 的延迟 在手机上绑定 click 事件,会使得操作有 300ms 的延迟,体验并不是很好。 开发者大多数会使用封装的 tap 事件来代替 click 事件,所谓的 tap 事件由 touchstart 事件 + touchmove 判断 + touchend 事件封装组成
iOS 点击会慢 300ms 问题
https://developers.google.com/mobile/articles/fast_buttons?hl=de-DE http://stackoverflow.com/questions/12238587/eliminate-300ms-delay-on-click-events-in-mobile-safari
-webkit-transform-style: preserve-3d;
-webkit-backface-visibility: hidden;
-webkit-touch-callout:none
<meta content="email=no" name="format-detection" />
-webkit-user-select:none
http://paulirish.com/2012/why-moving-elements-with-translate-is-better-than-posabs-topleft/
window.scrollY
window.scrollX
比如要绑定一个 touchmove 的事件,正常的情况下类似这样(来自呼吸二氧化碳)
$('div').on('touchmove', function(){
//.….code
});
而如果中间的 code 需要处理的东西多的话,FPS 就会下降影响程序顺滑度,而如果改成这样
$('div').on('touchmove', function(){
setTimeout(function(){
//.….code
},0);
});
把代码放在 setTimeout 中,会发现程序变快.
解决方法删除了 overflow-x:hidden; 然后在JS生成下来菜单之后 focus 聚焦,这两步操作之后解决了问题。(来自岛都-小Qi)
IE10
消除 IE10 里面的那个叉号
input:-ms-clear{display:none;}
来源出处:http://msdn.microsoft.com/en-us/library/windows/apps/hh767361.aspx
IE10 的特殊鼠标事件
http://www.mansonchor.com/blog/blog_detail_73.html
可以通过正则去掉
this.value = this.value.replace(/\u2006/g, '');
但支持display:-webkit-box这种写法的布局,
相关的属性也要相应修改,如-webkit-box-pack: center;
移动端采用弹性布局时,建议直接写display:-webkit-box系列的布局
解决方案是在触发函数里面加上e.preventDefault(); 记得将e也传进去。
transform的时候,加上类似translateZ(0px),有助于开启硬件加速.也看到有人说,现在不加z轴,也会开启硬件加速,这个我还没找到确切依据,不过加上不麻烦,我一般都是加上的.
做透明的样式,background:RGBA(x,x,x,x)和ps对应的更好,opacity我主要用于动画效果
-webkit-tap-highlight-color:rgba(0,0,0);
在Android的高级版本中可能还会出现黄色边框,去除:outline:none;
解决方案:解析图片的EXIF信息,使用其中的orientation字段,根据方向调整图片。参考:https://www.imququ.com/post/how-to-auto-rotate-photo-in-js.html
2、 手机上传图片会变横,比如:竖着拍照上传,图片不是竖的,而变成横的。这个也不是微信的问题,是因为我以前还没在手机上做过图片上传,所以第一次遇见。
解决方案:解析图片的EXIF信息,使用其中的orientation字段,根据方向调整图片。参考:https://www.imququ.com/post/how-to-auto-rotate-photo-in-js.html
4、 一些Android手机,比如三星Note3,从SD卡中选择图片上传,会提示“请选择SD卡中的图片”。我理解这个SD卡是指外接SD卡,直接从手机内置存储中选择图片是可以上传成功。
5、 Android4.4下由于系统WebView的openFileChooser接口更改,导致无法选择文件,从而导致无法上传文件。现在,大多数浏览器都修复了此BUG,但当前版本5.3的微信内置WebView并未修复。参考:https://code.google.com/p/android/issues/detail?id=62220
目前Android4.4版本系统占比上升非常快,从目前监控数据来看,1个月内上升了2%,当前Android4.4总占比超过5%,希望微信能尽快修复此BUG。
目前最新进展:Android 4.4.3+ 以上的版本已经修复了这个BUG。
通过后期和同僚交流,得知微信不会主动清空缓存。可能是因为Android设置setDomStorageEnabled开启缓存,但没有设置存储目录,导致缓存被存储到临时目录中,临时目录就有被自动清除的可能。参考:http://stackoverflow.com/questions/2961460/my-android-html-application-is-losing-values-stored-in-localstorage-when-it-shut/5418555
可以确认cookie不会被主动清除。如果将微信进程杀死,过期时间为session状态的cookie会被清除。如果用户主动退出微信登入,所有cookie都会被清除。
得到一些新的反馈:1、有小部分安卓机器cookie/localstorage都失效,目前微信那边没有好的解决方案;2、一般来说cookie + localstorage就能解决大部分问题。我现在使用了cookie + localstorage双备份的策略。
在微信下,一切本地存储的方式都是不靠谱的,唯一靠谱的是微信开发API,使用微信的用户OpenID来跟踪用户。
1】. 动态加载某个模块,发现iscroll 没有 效果。
【2】. 使用jquery 的 (slideDown、slideUp )动画效果,发现iscroll的滚动条算高度会有问题。
【1】【2】的 解决方案:setTimeOut(function(){ new IScroll("#wrapper") },100);
【3】:iscroll里面的a链接点击没有效果。
解决方案:找到 preventDefaultException: { tagName: /^(INPUT|TEXTAREA|BUTTON|SELECT|A|IMG)$/ } 这句话,去掉 |A,就可以了,因为默认禁用了。
【4】:使用iscroll拖动到顶部,加载下一页数据。(此部分完全可以抽出来,做成一个通用的分页,偸了个懒)
tap 点透 问题】------------------------
起因:由于我给页面大量用了 tap, 解决了click点击的延迟问题,同时也带来了新的问题。
如果我给document绑定tap事件,如果,弹层模板下面,有个元素也绑定了,此时就会出现点透的问题。
推荐 大家可以看看 , 叶小钗 关于 “点透” 问题的文章分析:http://www.cnblogs.com/yexiaochai/p/3442220.html
解决方案:fastclick , 确实是解决了这个问题。
解决方案地址:http://blog.youyo.name/archives/zepto-tap-click-through-research.html
小屏幕显示大网页
缩放
480px屏幕显示320px网页
布局中的pixel ≠ 屏幕上的pixel
高分辨率图片的使用
为什么iPhone4上看是模糊的?不是说iPhone4屏幕效果更好吗?
移动设备上通常用touch事件而非mouse事件
WP没有touch,还是用mouse
touchstart -> touchend的过程通常比click事件更灵敏
可以用这个特点来自己制作快速点击的事件
iOS较新版本支持很多点,而Android直到2.3还是只支持一个点
双指缩放图片
大多数手机和浏览器都有惯性滑动
惯性滚动停止以后才触发onscroll事件
有的手机和有的UCWeb下面是以抽筋一样的频率触发
scroll周边问题
有的浏览器下取窗口滚动位置不准确
不支持
iOS 5支持
诡异的1px来回抖动
Android 2.3支持
版本和第三方定制差异,可用性较低
iOS下OK
Android下弹出虚拟键盘时常会造成悲剧
使用一个height:100%的绝对定位div来取高度
硬件加速?忽悠?
Android有时候会和rotate冲突
这种时候即使用TransformMatrix都不给力
性能!性能!性能!
卡:少用特效
虚:参考“卡”,碰运气
闪:-webkit-backface-visibility:hidden; -webkit-perspective:1000;
在软件盘弹出之后,如果想点击一个按钮又不希望软键盘收起,可以在touch事件中调用e.preventDefault()防止软键盘被收起。这个例子可参见百度移动搜索首页的文本框,输入内容之后,点击右侧的“X”按钮清空输入,但软键盘不会收起。