问题
IOS下,当input唤起软键盘,fixed会失效变成absolute定位,如果说body的长度超过了屏幕长度,也就是说body是滚动的,那么导致的结果是原本fixed定位的模块都会表现成跟随body一起滚动了
栗子🌰
栗子中测试
- 常规的代码
1 | <template> |
- BUG现象
未唤起软键盘,页面正常

唤起软键盘,fixed失效

不一样的webview反应不太相同,上面的截图是在钉钉端(非wkwebview内核),在fixed失效的同时,错误定位在失效之前该模块对应在正常文档流中的那个位置,截图展示如下
现在我滚动到底栏在第四个图的中间位置,顶栏大概在第一个位置的1/3处

然后唤起软键盘后,fixed失效并正好定位在失效之前的位置,header和footer都是


这种情况除外,在safari中以及微信(wkwebview内核)上fixed失效但不会定位到失效前对应的位置,还是正常定位了top:0及bottom:0
如下是在微信上截图,也是在上次的位置唤起软键盘,但是没错误定位,如下:

分别滚动到底部和顶部,如期就在原始的定位位置


这种差距和这篇博客没关系,暂不讨论,总之结果是fixed会失效
解决方案
采取的方式是利用CSS更改布局来搞定,存在这个问题有个前提是body长度超出了屏幕高度,如此fixed失效成为absolute才会有影响,如果说本身body都没有超过高度,那么即便是absolute定位也是能正常在顶部或底部,所以,解决方式一是让body长度不超过屏幕高度,内容多就放在某个元素里滚动,比如放在main中滚,不让body滚动
更改代码:
1 | main{ |
验证是可以的,不过有个新坑,就是input掉下来一截,没有正好在软键盘的上部,当输入内容后才会再次弹上来在软键盘上面,这和使用的不是原软键盘有关,看下差别
原软键盘,没问题:

搜狗软键盘,掉下来一截:

对比可见其实input定位一样,是搜狗软键盘会高一些些,如图:

应该不少数人用第三方输入法吧,特别是女生喜欢更换各种输入法皮肤,所以这个bug出现率很高
查阅资料IOS唤起软键盘的过程是通过滚动可视窗口让输入框滚动上来,也就是document.body.scrollTop()会改变(安卓的方式是改变window.height()), IOS会遮挡输入框, 是因为,第三方输入法的tool bar或者键盘也被当做可视区域了(包含在键盘弹出时的window.innerHeight),所以滚动得低了
针对解决方式也是搜集大量的资料,看别人的总结,方法多样,比如说底端input就是个摆设,点击它时展示一个真正让用户输入的input紧贴软键盘上方,我觉得方法麻烦没尝试,更多的方法是说唤起键盘时自己控制下body的滚动,既然之前滚动的不够,那就自己控制让其滚动到最底端,大致思路如此,实现存在不少形式,比如由于没有监听键盘被唤起的事件,所以监听事件的选择很重要,对于安卓来说唤起键盘后是会有resize事件,但是IOS不会触发resize,那随之自然想到focus事件,但是唤起键盘是个过程,需要一定的时间,触发focus时可能这个过程还没结束,自然又会想到用setTimeout()事件做延时执行,实际尝试下来,效果不好,又换成setInterval()不断触发,使用感更好,滚动部分直接赋值页面内容高度了,最后总结觉得比较好的方式是:
1 | <template> |
效果:

PS:这里只是缓解IOS唤起软键盘导致fixed失效导致页面错乱,顺便处理了IOS的输入框被软键盘隐藏的bug,至于安卓软键盘遮住输入框的情况暂时没测
又调了代码,失去焦点的时候clearInterval(),代码如下:
1 | <template> |