发现问题

最近在工作项目中发现,html表单元素获得焦点时,移动端 Android 系统下自动弹出的软键盘会遮挡住表单元素。

这直接导致当页面高度在一屏以内,或表单元素无法通过滚动页面而移动时,用户无法在输入过程中看到元素本身内容。

这个问题在 IOS 下由于其自身的软键盘bug问题,反而不受影响。但很明显,这样的交互效果对于 Android 用户是很差的。

解决思路

发现这个问题后,我先尝试上网查询了一下大家遇到此类问题的解决办法,发现如果是原生app开发时可以通过设置 <activity>标签定位属性来控制。但是对于 html 来讲,通过 js 控制软键盘比较困难。

继续查找后发现下面这篇帖子:

有没有对web移动端安卓键盘遮挡输入框一类的原理详细介绍的博客

因为 window.innerHeight 可以获得不计算软键盘在内的窗口高度,受其启发我尝试了更换思路。通过对比“元素的纵坐标(相对于窗口)”与“窗口高度(不计软键盘)”的大小,来控制元素的定位。

最终得到了较为满意的效果。


需要注意的是:

  1. 因为软键盘弹出是动画效果,所以需要设置 setTimeout 延迟获取 window.innerHeight 。

  2. JS获取 offsetTop 属性是相对于父元素定位的,通常需要获取位置的元素都不是在最外层,而遍历上级元素的offset相关属性将导致影响脚本效率。这里使用浏览器接口 getBoundingClientRect 更加高效。

  3. getBoundingClientRect 浏览器兼容性:

    ChromeFirefoxInternet ExplorerOperaSafari
    1.03.0 (1.9)4.0(Yes)4.0
    • 语法:obj.getBoundingClientRect().top ;

    • IE 中只能获得 lefttopbottonright的属性值,而现代浏览器还能获取到元素的 width 和 height ;

    • bottom & right是元素底部(/右侧)相对于窗口顶部(/右侧)的距离,不是像css里面position的bottom相对于窗口底部。