移动端虚拟键盘和滚动穿透小结

记录一下最近遇到的两个小bug,也不算小bug,可能在不同的移动端浏览器表现不同吧。一个是虚拟键盘顶起,一个是滚动穿透问题。

虚拟键盘

首先需要明确的一点是,虚拟键盘的顶起在IOS端和Android端有很大的不同变现。

监听移动端软键盘弹起和收起

1. Android端 监听resize

1
2
3
4
5
6
7
8
9
10
11
var winHeight = $(window).height();

$(window).resize(function () {
var thisHeight = $(this).height();

if( winHeight - thisHeight > 140) {
// 键盘弹起,140px是一个预估值,可更改
} else {
// 键盘收起
}
})

2. IOS端 监听input失焦blur

ios中的键盘或者第三方键盘并不会监听到window resize事件,所以不能用resize监听,所以需要通过输入框是否获取焦点来判断。

在Android中,有一些机型,键盘收起了,输入框仍处于焦点状态,并没有触发focusout事件。

因为focusinfocusout支持冒泡,对应focus和blur,所以根据需求,我们可以选择相应的事件。

1
2
3
4
5
6
7
$(document).on('focusin', function () {
  //软键盘弹出的事件处理
});

$(document).on('focusout', function () {
  //软键盘收起的事件处理
});

input textarea contenteditable="true" 置底问题

这里也需要了解一下,IOS和Android关于fixed属性的支持是不一样的。

1. IOS端

ios中,虚拟键盘顶起来之后,整个页面都会被键盘部分压缩。也就是说页面的高度会变小,并且所有的fixed都会变成absolute

也就是说,之前在ios端fixed到底部的input框等可focus元素,会变成absolute定位,并且随着页面能够滑动。

2. Android端

android端中,虚拟键盘顶起来之后,fixed属性不会失效,唤起的键盘是覆盖在页面上的,不会压缩页面。

项目中的bug及一些思考

在最近的一个项目中,移动端页面布局,因为现在手机的高度不同,简单的背景图并不能放文字了,文字会拉伸,我需要设置一个footer放到底部,这里我最开始考虑的就是用fixed布局到最底部,结果当键盘顶起来的时候,文字也就跟着一起顶上去了,整个页面使用的是overflow: hidden

这里就需要监听键盘顶起事件,并执行相应的给元素添加相关css的功能。

1
2
3
4
5
6
7
8
9
var oHeight = $(document).height();
// 监听键盘事件
$(window).resize(function () {
if ($(document).height() < oHeight) {
$('footer').addClass('hide');
} else {
$('footer').removeClass('hide');
}
});

另外,关于底部的输入框顶起的问题,我看了一下手机版微博的解决方案,在Android端,虚拟键盘顶起,应该直接是fixed在底部,在IOS端则是整个添加了一个评论的浮层,总来来说也是一个不错的方案。

最后介绍一个神奇的东西Element.scrollIntoView(),这个东西能把底部的输入框提高到可视区域,不过经过测试,键盘顶起是需要时间的,我们需要确保,在键盘调起之后,确保元素调用scrollIntoView()

下面是我写的一段代码:

1
2
3
4
5
$('#el').on('focus', function () {
setTimeout(() => {
document.querySelector('#el').scrollIntoView();
}, 300);
});

滚动穿透

在移动端中,滚动穿透问题很常见,处理起来也比较繁琐。下面我还是按照不同的方法进行分类:

touchmove事件中调用preventDefault()

这个方法适用于,弹出框内容无需滚动。如果弹出层内部有滚动事件,将会导致,弹出层的滚动事件也无法滚动。

添加相关的类

给html上添加一个noscroll的类

1
2
3
4
5
.noscroll,
.noscroll body
overflow: hidden
.noscroll body
poition: relative

缺点:

  1. html和body的滚动都禁止了,弹出层关闭后,会丢失原有的滚动位置,需要用JS来还原
  2. 有些页面的北京还有能滚的动的效果

fixed加上js恢复记录位置

css

1
2
3
4
body.mask-open {
position: fixed;
width: 100%;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var scrollTop = 0;

open.onclick = function() {
scrollTop = document.body.scrollTop || document.documentElement.scrollTop;

document.body.classList.add('mask-open');

document.body.style.top = -scrollTop + 'px'; // 脱离文档流后回到当前位置

mask.style.display = 'block';
}

close.onclick = function() {
mask.style.display = 'none';

document.body.classList.remove('mask-open');

document.body.scrollTop = document.documentElement.scrollTop = scrollTop // 滚动到相应位置,确保兼容性
}

参考