Preface
Recently, in webapp, there are many mobile compatibility problems, one of which is that after the input box triggers focus, the keyboard pops up, and then blocks the input box.
Then on Android and IOS, the problem is not the same, and the native keyboard is not the same as the third-party keyboard, but the problem is the same: the input box is blocked.
Desired effect
When the keyboard pops up, the input box to get the focus should be in the visible area, and the effect is as follows:
Keyboard pop-up and pop-up performance
-
IOS:
The input box gets the focus, the keyboard pops up, the webview height will not change, but the webview will roll up, and the maximum scrollTop is the keyboard height.
When you click the stow button on the keyboard or the page area outside the input box, the input box loses focus and the keyboard is stowed.
-
Android:
The input box gets the focus and the keyboard pops up, but the webview height will change. The height is the original height minus the height of the soft keyboard.
When clicking the area outside the input box, the input box loses focus and the soft keyboard is folded up. When you click the stow button on the keyboard, the keyboard will stow, but the input box will not lose focus.
Solution
When the input box is blocked, in IOS, webview will roll up a certain distance, so that the input box to get the focus will automatically be in the visible area, while in Android, only the height of webview will be changed, and the focus element will not roll to the visible area.
So IOS doesn't matter. Android needs to scroll the input box to the visual area when the keyboard pops up.
Get device type
First, get the device type through navigator.userAgent.
const judgeDeviceType = (() => { let deviceType = null; return () => { if (!deviceType) { const ua = window.navigator.userAgent.toLocaleLowerCase(); const isIOS = /iphone|ipad|ipod/.test(ua); const isAndroid = /android/.test(ua); const isMiuiBrowser = /miuibrowser/.test(ua); deviceType = { isIOS: isIOS, isAndroid: isAndroid, isMiuiBrowser: isMiuiBrowser }; } return deviceType; }; })();
Monitoring events
IOS can pop up and shut down through focus and blur events, but Android can't, but because the webview height will change, it can be solved by listening to resize events.
export function listenAndroidKeybord() { const { isAndroid } = judgeDeviceType(); if (isAndroid) { const androidResize = function() { // Scroll the current focus element to the viewable area activeElementScrollIntoView(); }; // When the android keyboard is ejected and folded up, the height of the visual area will change window.addEventListener('resize', androidResize, false); return () => { window.removeEventListener('resize', androidResize, false); }; } }
Scroll elements to view
There are two main methods to scroll elements to the visual area: scrollIntoView and scrollIntoView ifneeded. The compatibility is very good on the mobile side.
function activeElementScrollIntoView() { const activeEl = document.activeElement; if ( activeEl.tagName === 'INPUT' || activeEl.tagName === 'TEXTAREA' ) { window.setTimeout(() => { if ('scrollIntoView' in activeEl) { activeElt.scrollIntoView(); } else { activeEl.scrollIntoViewIfNeeded(); } }, 100); } }
MiuiBrowser
The above code can be said to solve most of the browser keyboard occlusion problems, but when I use my own millet mobile phone's millet browser test, there is a problem, the keyboard pops up, the page is still, drag manually, sometimes OK, sometimes not.
After a long time, I found two problems. The Xiaomi browser on my mobile phone doesn't have the Android logo on the userAgent, but it has the MiuiBrowser logo. Then, sometimes the page can be dragged, sometimes it can't be dragged. I guess it's due to the height change of the visual area of webview, or my code listening to resize.
Solution
-
Add equipment type judgment
const ua = window.navigator.userAgent.toLocaleLowerCase(); const isMiuiBrowser = /miuibrowser/.test(ua);
-
Listen to the keyboard pop-up, pop-up, and then increase the height of the body by listening to the focus and blur events
body, html { height: 100%; }
function listenMiuiBrowserKeybord() { const { isMiuiBrowser } = judgeDeviceType(); if (isMiuiBrowser) { const inputFocus = function() { document.body.style.marginBottom = '50px'; activeElementScrollIntoView(); }; const inputBlur = function() { document.body.style.marginBottom = '0px'; activeElementScrollIntoView(); }; let $inputs = document.getElementsByTagName('input'); for (let i = 0; i < $inputs.length; i++) { $inputs[i].addEventListener('focus', inputFocus, false); $inputs[i].addEventListener('blur', inputBlur, false); } return () => { for (let i = 0; i < $inputs.length; i++) { $inputs[i].removeEventListener('focus', inputFocus, false); $inputs[i].removeEventListener('blur', inputBlur, false); } }; } }
Pit: Although this solution solves the pop-up problem, click the keyboard stow button, the input box under Android will not lose focus, and you need to lose focus to make the height of the body increase to 0.
Remarks
The solution is not perfect and there is a long way to go.