Android неправильно прокручивает фокус ввода, если не элемент body
Когда мобильный браузер вызывает клавиатуру, он пытается переместить полосы прокрутки так, чтобы ввод оставался видимым.
В iOS Safari он, кажется, делает это правильно, находя ближайшего прокручиваемого родителя.
В родном Android-браузере или мобильном браузере Chrome кажется, что он просто пробует элемент body, а затем сдается, поэтому сфокусированный ввод скрыт под клавиатурой.
Как это сломать
Задавать overflow-y: hidden
на элементе тела. Создайте прокручиваемый контейнер и поместите туда форму.
Когда вы выбираете элемент в нижней части экрана, он будет скрыт клавиатурой.
демонстрация
http://dominictobias.com/android-scroll-bug/
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"/>
<title>Android scroll/focus bug</title>
<style>
html, body {
margin: 0;
padding: 0;
height: 100%;
overflow: hidden;
}
.scroll {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
overflow-y: scroll;
}
input {
margin-bottom: 20px;
width: 100%;
}
</style>
</head>
<body>
<div class="scroll">
<input type="text" value="Input 1">
<input type="text" value="Input 2">
<input type="text" value="Input 3">
<input type="text" value="Input 4">
<input type="text" value="Input 5">
<input type="text" value="Input 6">
<input type="text" value="Input 7">
<input type="text" value="Input 8">
<input type="text" value="Input 9">
<input type="text" value="Input 10">
<input type="text" value="Input 11">
<input type="text" value="Input 12">
<input type="text" value="Input 13">
<input type="text" value="Input 14">
<input type="text" value="Input 15">
<input type="text" value="Input 16">
<input type="text" value="Input 17">
<input type="text" value="Input 18">
<input type="text" value="Input 19">
<input type="text" value="Input 20">
</div>
</body>
</html>
Любые идеи, как это исправить? Это потребует некоторого обнаружения браузера и грязных взломов?
4 ответа
Это ошибка в родном браузере Android. Кстати, ввод прокручивается в представление после того, как на клавиатуре набирается символ.
Следующий фрагмент кода, размещенный где-то на странице, должен помочь:
if(/Android 4\.[0-3]/.test(navigator.appVersion)){
window.addEventListener("resize", function(){
if(document.activeElement.tagName=="INPUT"){
window.setTimeout(function(){
document.activeElement.scrollIntoViewIfNeeded();
},0);
}
})
}
Ответ Сергея великолепен, но у меня было несколько модификаций, которые улучшили его для меня.
Проблема появилась на Android 6 и для меня, поэтому я добавил ее к проверке, и мне нужно было исправление, чтобы работать как с текстовыми областями, так и со входами.
if(/Android [4-6]/.test(navigator.appVersion)) {
window.addEventListener("resize", function() {
if(document.activeElement.tagName=="INPUT" || document.activeElement.tagName=="TEXTAREA") {
window.setTimeout(function() {
document.activeElement.scrollIntoViewIfNeeded();
},0);
}
})
}
Если кому-то нужно исправить в Angular 1, вот что я использовал там.
angular.module('<module name>').run(function ($window, $timeout) {
if(/Android [4-6]/.test($window.navigator.appVersion)){
$window.addEventListener("resize", function(){
if(document.activeElement.tagName=="INPUT" || document.activeElement.tagName=="TEXTAREA"){
$timeout(function() {
document.activeElement.scrollIntoViewIfNeeded();
});
}
});
}
});
Предлагая небольшую доработку, если это кого-то экономит:
- Не нужно указывать версию Android # (меньше вероятности поломки, когда ваш пользователь получит Android 7.0+)
- Не нужно оборачивать в setTimeOut
МДН советует против
.scrollIntoViewIfNeeded
bc несовместимости браузера =>.scrollIntoView
является работоспособной заменой с немного большей совместимостью с браузеромif(/Android/.test(navigator.appVersion)) { window.addEventListener("resize", function() { if(document.activeElement.tagName=="INPUT" || document.activeElement.tagName=="TEXTAREA") { document.activeElement.scrollIntoView(); } }) }
Если взглянуть на это немного иначе, то, похоже, ошибка вызвана функцией "Предложения" в браузере. Поскольку я действительно не хочу предложений, так или иначе, я использовал:
if(/Android/.test(navigator.appVersion)){
$('input[type="text"]').attr('autocomplete', "off");
}
что дает гораздо более плавный опыт.