iOS浏览器中fixed元素失效问题

最近参与一个ios混合App的开发,是挺大的一块功能,而且设计上是与原生风格一致的,即看设计图感觉不到这是网页。为了方便流程控制,就把整个屏幕区域交给了H5,H5有自己的标题栏,而且是fixed的,到这里还没有大问题,当fixed元素遇到文本框,问题就来了。

上一个Angular的 demo ,请用iphone查看,先往上滚屏,标题栏固定在顶部,没有问题。现在点击某个文本框,虚拟键盘弹出,这里滚动页面,发现标题栏定位已经失效了!无论是ios Safari(情况可能会好一些)或UIWebView,都有这个问题,来个截图:

223F185918DAAD9518B5E10740E194CC

经过一番google,查到这是Apple的一个设定,考虑到虚拟键盘已经占了很大一大块屏幕了,剩下的内容如果再有固定元素,那么可滚动查看的内容区域将更加小,所以当虚拟键盘弹出时,取消fixed元素的固定定位!但是这个『取消』有些蹩脚,在我们这个例子里,标题栏在页面中间的某个位置『绝对定位』了,太丑了,表示难以接受囧。

继续google,有人说可以在文本框获取焦点时,将fixed元素设置为absolute定位。尝试一番,效果比原来好了一些,而且也不违背Apple的设计,请看 优化版 。关键代码:

1
2
3
4
5
6
7
element
.on('focus', function () {
J_fixed.addClass('abs');
})
.on('blur', function () {
J_fixed.removeClass('abs');
})

嗯,效果已有所改善,但在我的项目中,有时候还是会定位失效囧。

于是,再尝试索性将标题栏通过某个手段定在顶部,请看 scroll事件版定位版 ,效果勉强接受,在滚动过程中,还是会随和页面移动,滚动停止时,才会触发scroll事件。关键代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var fixTop = function () {
var winScrollTop = J_win.scrollTop();
J_fixed.css('top', winScrollTop);
};
element
.on('focus', function () {
J_fixed.addClass('abs');
J_win.on(FIX_FIXED_EVENT_NAME, fixTop);
fixTop();
})
.on('blur', function () {
J_fixed.removeClass('abs');
J_win.off(FIX_FIXED_EVENT_NAME);
J_fixed.css('top', 0);
})

再试试另一个 定时版 ,关键代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var timer;
var fixTop = function () {
var winScrollTop = J_win.scrollTop();
J_fixed.css('top', winScrollTop);
};
element
.on('focus', function () {
J_fixed.addClass('abs');
timer = $interval(fixTop, 20);
})
.on('blur', function () {
J_fixed.removeClass('abs');
J_fixed.css('top', 0);
$interval.cancel(timer);
})

表面上看似乎效果与scroll版差不多,但据我的经验,这种方式会更可靠一点点,scroll事件不是太靠谱,定时的方式缺点是比较耗cpu,因为是频繁计算,可以将时间间隔改短一点,节省CPU。

 

另外,再送一点干货:

ios下弹出纯数字键盘方式:

1
<input type=”text” pattern=”\d*”>


1
<input type=”number” pattern=”\d*” >

 

隐藏键盘代码:

1
$('input:focus, select:focus').blur();

 

再扯点别的。

前几个礼拜的文章里,提到会尽量抽时间研究ReactJS,很抱歉,我没有做到,因为时间都投身在一线项目里了囧,包括加班也是赶项目。差不多一个礼拜前,甚至又在AngularJS和ReactJS之间动摇,到底公司新架构应该推哪一个呢。就在这两天,重新确定,『回到』ReactJS的怀抱,似乎React更可能是未来的方向,尤其是与Node的结合,以及React Native,这是一个长远的理想,Fighting!