Android не выполняет корректную прокрутку по фокусу ввода, если не элемент тела

Когда мобильный браузер вызывает клавиатуру, он пытается переместить полосы прокрутки таким образом, чтобы вход все еще находился в поле зрения.

В iOS Safari, похоже, это делается правильно, если найти родителя прокрутки ближайшего.

В Android-браузере или на мобильном браузере Chrome он просто пытается создать элемент body, а затем сдается, поэтому сфокусированный вход скрыт под клавиатурой.

Как разбить его

Установите overflow-y: hidden в элемент body. Создайте прокручиваемый контейнер и разместите там форму.

Когда вы выбираете элемент в нижней части экрана, он будет скрыт от клавиатуры.

Demo

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>

Есть идеи, как это исправить? Будет ли это требовать обнаружения браузера и грязных хаков?

Ответ 1

Это ошибка в собственном браузере 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);
      }
   })
}

Ответ 2

Ответ от Сержа велик, но у меня было несколько модификаций, которые улучшили его для меня.

Проблема появилась и на 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();
                });
            }
        });
    }
});

Ответ 3

Предлагая небольшую ревизию, если она кого-то кого-то экономит:

  • Не нужно указывать версию Android версии # (менее вероятно, чтобы сломаться, когда ваш пользователь получит Android 7.0 +)
  • Не нужно обертывать setTimeOut
  • MDN советует против .scrollIntoViewIfNeeded bc несовместимости браузера = > .scrollIntoView является работоспособным заменителем с немного большей совместимостью с браузером

    if(/Android/.test(navigator.appVersion)) {
       window.addEventListener("resize", function() {
         if(document.activeElement.tagName=="INPUT" || document.activeElement.tagName=="TEXTAREA") {
           document.activeElement.scrollIntoView();
         }
      })
    } 
    

Ответ 4

Если посмотреть на это немного по-другому, ошибка, как представляется, вызвана функцией "Предложения" браузера. Поскольку я вообще не хочу предложений, я использовал:

if(/Android/.test(navigator.appVersion)){
  $('input[type="text"]').attr('autocomplete', "off");
}

что дает гораздо более плавный результат.