最近在工作中遇到了一个关于手机端IOS系统的第三方软键盘唤起导致底部输入框被遮挡的问题,具体情况是要求实现一个手机端在线聊天页面,需要仿微信的聊天页面,一开始整个页面的布局是这样的:
基本HTML结构
<div class="nav"></div> <div class="content"></div> <div id="returnframe"> <input type="text" name="inputframe" class='inputframe'> <div class="returnframe_button">发送</div> </div>
CSS
/*聊天窗口_顶部*/ .nav{ display:block; position:fixed; top:0; width:100%; height:50px; font-size:2rem; background-color:#393a3f; z-index:99; } /*聊天窗口_内容*/ .content{ display:block; position:absolute; top:50px; bottom:50px; width:100%; height:auto; background-color:#ebebeb; overflow-y:scroll; -webkit-overflow-scrolling:touch; } /*聊天窗口_底部*/ #returnframe{ display:block; position:fixed; bottom:0; width:100%; height:50px; background-color:#f4f4f4; border-top:1px solid #d8d8d8; z-index:99; }
顶部栏和底部输入栏使用的是相对于视窗定位的fixed固定定位,中部聊天窗口使用的是absolute绝对定位,同时设定其距离顶部和底部50(顶部和底部的高度),overflow-y:scroll(若中部聊天窗口内容过长则使用滚轮显示超出部分的内容)
该布局在Android的系统中不论是系统自带还是第三方软键盘唤起时都没有出现输入框被遮挡的现象,而在苹果的IOS系统环境下则出现了遮挡现象
最初在网上搜集解决的办法中了解到,IOS对于CSS的fixed固定定位支持程度并不好,即便是部分Android机型对其兼容性也较低,极易出现各种奇葩的BUG,举例如下
- 本次遇到的输入框被遮挡
- 输入框被顶到屏幕中央
- 顶部栏消失或定位异常等
经过思考和资料查阅,可以总结出以上问题发生的根本原因:
- 手机端对于CSS的fixed固定定位本身加兼容性不佳,导致fixed失效或被默认变成为absolute定位,使布局发生变化
- 第三方输入法,以百度输入法为例,在输入时会有一个toolbar,这就导致即使输入框已经随软键盘弹起,但正好被toolbar挡住绝大部分内容
- 部分键盘可能浮动于上层,在不影响布局的前提下恰好对输入栏形成了视觉遮挡
根据问题发生的根本原因,通过网络资料查阅,整理出以下的大人们的部分解决方案
以下是各种解决方案:
使用 ionic-plugins-keyboard 插件或者使用 cordova-plugin-keyboard 插件解决原理:通过插件中的方案从而监听键盘弹出事件或者改变布局结构,使键盘弹出时整体界面上移优点:统一在Android和IOS系统上的体验效果,在达到目的的同时减少触发其他BUG的可能缺点:插件的导入会增大文件的整体体积,同时影响页面响应时间
原理:若内容在可视域内则它什么也不做,若不在可视域,则使输入框出现在可视域范围内
优点:解决方法简单,较为折中
缺点:可能会触发其视觉上的bug,实现的效果不确定,即输入框出现的位置在各个设备上有所差别甚至没有得到解决
修改设计稿,尽量使输入框不再页面的50%以下部分,或采用分页设计和弹出输入层
原理:通过更改设计稿的设计,使页面中的输入和相关内容尽量出现在页面的上50%部分,或者将输入框设置为弹出层,输入时弹出层赞软键盘上方,从而使键盘弹出时不造成遮挡,影响视觉
优点:根本上避免软键盘遮挡输入内容的问题
缺点:更改设计稿在设计前就和设计师充分沟通,但不是总能在进行每个项目时都能及时赶上,同时不能确定设计师和客户是否会做出让步(嗯,你懂的)
原理:通过js监听resize事件同时实时获取或计算每一种弹出的软键盘高度以改变输入框位置
优点:简单粗暴
缺点:若不是在底层Android编程时实现,仅通过js拿不到键盘的弹起/收起事件,同时ios上键盘弹起/收回不会触发window.resize事件,android4.4以下, 键盘唤起时, 不仅会触发resize, 还会额外会触发scroll事件,整体上造成出现了各种新的不确定因素
通过js实时获取webview的变化来使软键盘弹出时,内容跟随变化
原理:通过Native.js,后去webview的高度,屏幕的高度,状态栏的高度,从而计算出每次弹出的软键盘的高度
优点:快速解决问题的同时能加深对js和native.js的理解
缺点:需要判断平台,同时要求使用者掌握的技术水平较高,因为Native.js是直接调用Native API,需要对Native API有一定了解,知道所需要的功能调用了哪些原生API,能看懂原生代码并参考原生代码修改为JS代码
原理:导入iScroll框架,通过它来模拟滚动效果,取代原有的滚动,从而在软键盘弹出,改变滚动条的同时改变输入框和页面的位置
优点:在解决问题的同时还能做其他拓展(iscroll是个轻量的好东西)
缺点:会对页面响应速度有些许影响,同时需要了解iScroll的各类参数设定
原理:判断是否是IOS终端,当输入框获得焦点时候,等待一定时间(键盘弹出动画时间)后滚动到页面底部
优点:实现方法较为简单,不依赖于第三方代码加入
最终解决方案
先参考该方案移动端iOS第三方输入法遮挡底部input及android键盘回落后留白问题
然后是自己理解后对自己代码的更改
CSS
/*聊天窗口_顶部*/ .nav{ display:block; position:absolute; top:0; width:100%; height:50px; font-size:2rem; background-color:#393a3f; z-index:99; } /*聊天窗口_内容*/ .content{ display:block; position:absolute; top:50px; bottom:50px; width:100%; height:auto; background-color:#ebebeb; overflow-y:scroll; -webkit-overflow-scrolling:touch; } /*聊天窗口_底部*/ #returnframe{ display:block; position:absolute; bottom:0; width:100%; height:50px; background-color:#f4f4f4; border-top:1px solid #d8d8d8; z-index:99; }
上面的CSS中,首先将顶部和底部原来的fixed固定定位修改为了absolute绝对顶为,从而避免fixed存在于各类手机端系统上的兼容性问题,同时避免在底部输入栏在定位形式发生改变时造成的居中显示问题
JS
//解决第三方软键盘唤起时底部input输入框被遮挡问题 var bfscrolltop = document.body.scrollTop;//获取软键盘唤起前浏览器滚动部分的高度 $("input.inputframe").focus(function(){//在这里‘input.inputframe’是我的底部输入栏的输入框,当它获取焦点时触发事件 interval = setInterval(function(){//设置一个计时器,时间设置与软键盘弹出所需时间相近 document.body.scrollTop = document.body.scrollHeight;//获取焦点后将浏览器内所有内容高度赋给浏览器滚动部分高度 },100) }).blur(function(){//设定输入框失去焦点时的事件 clearInterval(interval);//清除计时器 document.body.scrollTop = bfscrolltop;将软键盘唤起前的浏览器滚动部分高度重新赋给改变后的高度 });
在第三方软键盘被唤起时,浏览器内所有内容高度发生了改变,将他赋给浏览器滚动部分高度,从而使页面改变,同时始终能在键盘唤起的相近时间内正确对应到相应位置,从而使输入框在视觉上能仅仅贴住被唤起的软键盘+toolbar顶端,解决了输入框被遮挡和或顶部栏消失问题
以上就是解决第三方软键盘遮挡输入框问题的方案。。