在IOS系统下的H5页面中,软键盘弹出会对页面布局产生一些问题,其中最典型的就是元素固定定位失效问题。
一、分析原因
当软键盘弹出时,在Android系统下,H5所在容器(即WebView)高度会被压缩,而IOS系统下则不会发生改变,软键盘是从底部弹出直接覆盖在WebView上的,从而造成部分内容会被软键盘遮挡,这时WebView出现滚动条。
一般情况下,固定定位可以让元素相对于WebView进行定位,但是软键盘的出现,导致相对于WebView定位的元素可能被遮挡,只有通过滑动页面的方式让被遮挡的元素显示出来,而这时固定定位就看起来似乎“失效”了。
上图虚线部分是设备的可视窗口,底部有个固定定位元素。当软键盘拉起时,该元素会被软键盘遮挡(如左图所示),此时WebView可滑动,上滑页面直至滚动条到最底部时,固定定位元素才能最终显示在软键盘顶部(如右图所示)。
如此可见,元素虽然还是相对于WebView进行定位,但由于软键盘遮挡而出现滚动条的缘故,导致固定定位看起来好像“失效”了。
接下来,我将以上述底部固定定位的案例来探讨具体解决固定定位失效问题的方案。
二、解决问题
以上案例基础页面布局代码如下:
<!-- HTML -->
<form id="form">
<textarea id="editor" cols="30" rows="10"></textarea>
<div id="toolbar">固定定位元素</div>
</form>
/* css */
html,
body,
form {
height: 100%;
}
form {
overflow: auto;
-webkit-overflow-scrolling: touch;
}
#toolbar {
position: absolute;
left: 0;
right: 0;
bottom: 0;
height: 50px;
}
1. 固定定位元素被软键盘遮挡问题
这个问题我们可以通过scrollIntoView()
方法来解决,scrollIntoView()
是DOM元素上的一个方法,该方法可滚动元素的父容器,使被调用scrollIntoView()
的元素对用户可见。
let editor = document.getElementById('editor'),
form = document.getElementById('form'),
toolbar = document.getElementById('toolbar');
// 编辑器获取焦点时滚动容器至toolbar元素可见
editor.addEventListener('focus', () => {
setTimeout(() => { // 延迟执行是为了保证键盘已拉起
toolbar.scrollIntoView();
}, 300);
});
2. 容器滚动导致编辑器不在可视区问题
当使用scrollIntoView()
后底部定位元素虽然可见,但也同时可能导致位于页面顶部的编辑器滚动到可视区之外。
要解决这个问题,我们可以直接在编辑器获取焦点时将底部定位元素的bottom
值设为软键盘高度,而软键盘高度无法直接获得,但可以通过上面scrollIntoView()
导致的容器滚动高度来间接获得。
let boardHeight = 0;
editor.addEventListener('focus', () => {
setTimeout(() => {
toolbar.scrollIntoView();
// 键盘高度 = 容器滚动高度
boardHeight = document.documentElement.scrollTop || document.body.scrollTop;
toolbar.style.bottom = boardHeight + 'px';
scrollTo(0, 0); // 最后记得要让页面回到顶部,让页面顶部的编辑器回到可视区内
}, 300);
});
3. 滑动页面时定位元素错位问题
由于固定定位失效而使用绝对定位替代,所以当我们滑动页面时,定位元素自然是不能始终固定在底部,而是随着页面滑动而上下移动。为了解决这个问题,我们可以在滑动页面时让软键盘拉起,并让定位元素的bottom
值重新回到初始值(本文例子是0)。
editor.addEventListener('blur', () => {
toolbar.style.bottom = 0;
});
document.addEventListener('touchmove', () => {
editor.blur();
});
结束语
本文介绍的方法并非最终完美的解决方案,比如当编辑器位于页面底部位置而非顶部时,该方案将会出现问题。如果看完本文觉得有不对之处或有更好解决方案,欢迎提出和指正,谢谢!