Nieyt's Blog

移动端h5吸底输入框被软键盘遮挡解决方案

字数统计: 1.1k阅读时长: 3 min
2018/05/17 Share

在移动web页面中,很容易遇到,位于页面底部的输入框,在获取焦点时,被弹起的软键盘遮挡的情况。近期的一个项目就面对了这样一个问题。

我们需要做的一个页面,视觉是这样的:

可选择的布局方案有很多种,我最终选择了flex布局,使输入框固定于页面底部。因为使用fixed定位会带来键盘弹起后输入框无法复位的兼容性问题,而使用absolute布局又需要手动计算聊天区域内容高度(calc(100vh-输入框区域高度)),相比之下flex布局写法简洁一些。

写完后,如果不做任何处理,我们会发现,在部分IOS手机上,使用第三方输入法,软键盘弹起时,会把输入框遮住。

于是,我们进行了下列处理:

第一阶段

软键盘弹起后(即输入框focus后)设置定时器,反复执行下面代码:

1
2
inputElement.scrollIntoView(true);  //元素的顶端与可视区域的顶端对齐
inputElement.scrollIntoViewIfNeeded();

或把以上代码换为:

1
document.body.scrollTop = document.body.scrollHeight;

对以上代码进行测试,结果发现:
IOS系统版本在11.0(>=11.0) - 11.3(<11.3)之间的手机,输入框都完全被软键盘遮挡(包括系统键盘和第三方键盘)。IOS系统版本不在此范围内的手机,以及安卓手机,使用自带键盘或第三方键盘,均未发现问题。

(以上结果的测试环境为微信内置浏览器,使用safari浏览器测,输入框会高出软键盘一小段距离。接下来的测试环境也均为微信内置浏览器)

原因解释:
IOS11.0-11.3 对scrolIntoViewscrollTop的解释有bug,直接执行会导致输入框滚到底部被遮挡。

第二阶段

发现当键盘弹起后不做任何处理时,IOS11.0-11.3的手机的自带输入法的软键盘不会遮挡输入框,但使用第三方输入法的输入框会被遮挡,原因是第三方输入法比IOS自带输入法多了一个toolbar,高度为88px,IOS系统未将其识别为软键盘的高度增加。为了优先兼容自带输入法,我们在代码中做了系统判断,如果手机系统版本在IOS11.0-11.3之间,则js不做任何处理,否则则执行以上强制滚动的代码。

我将以上代码写成了插件形式,代码地址为:https://github.com/nieyt/input-show

后期优化方向: 兼容特殊版本区间的第三方输入法;提高键盘弹出及收起时在观感上的流畅度

其他踩坑&思考

  1. 发现键盘弹起时使用scrolIntoViewscrollTop方法,输入框依然被遮挡的手机,键盘弹起时window.innerHeight未发生改变。我们可以在输入框focus时使用定时器延时获取键盘弹起时window.innerHeight的高度,与页面初始window.innerHeight的高度进行对比,如果未发生改变,则不执行scrolIntoViewscrollTop等方法。但这样做的缺点是,我们无法知道键盘弹起的延时时间,只能设置较长的延时时间,导致判断延时过长。

  2. 第三方输入法比系统输入法多出88px的toolbar,我们可以用position: absolute布局页面,当键盘弹起时,设置inputElement.css('bottom', '88px'),可兼容使用第三方输入法手机的输入框不被遮挡,但会导致使用系统自带输入法的手机,输入框距离键盘位置高出88px。由于上一条所说的,部分手机上软键盘弹起时页面window.innerHeight不发生改变,所以我们无法通过window.innerHeight来判断输入框是否在可视区域内(使用document.documentElement.clientHeight也同window.innerHeight,不发生改变),因此无法判断手机使用的是哪种输入法。

  3. 既然没有找到完美的解决方案,我们也可以从产品设计上做出改变,比如和产品商量在输入框下面增加一条横栏(比如工具栏设计等),只要该横栏高于88px就行,就再也不用担心第三方输入法遮挡输入框的问题啦。像这样(毫无违和感):

CATALOG
  1. 1. 我们需要做的一个页面,视觉是这样的:
  2. 2. 第一阶段
  3. 3. 第二阶段
  4. 4. 其他踩坑&思考