web-dev-qa-db-ja.com

Android body要素でない場合、入力フォーカスで正しくスクロールしません

モバイルブラウザがキーボードを表示すると、入力がまだ表示されるようにスクロールバーを移動しようとします。

IOS Safariでは、nearestスクロール親を見つけることにより、これを適切に行うようです。

AndroidネイティブまたはChromeモバイルブラウザでは、body要素を試してからあきらめているように見えるため、フォーカスされた入力はキーボードの下に隠れています。

それを壊す方法

セットする overflow-y: hiddenはbody要素にあります。スクロール可能なコンテナを作成し、そこにフォームを配置します。

画面の下部近くにある要素を選択すると、キーボードによって隠されます。

デモ

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>

これを修正する方法はありますか?ブラウザの検出と厄介なハックが必要ですか?

17
Dominic

これは、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);
      }
   })
}
49
Serge

Sergeからの回答はすばらしいですが、いくつかの変更を加えて改善しました。

この問題は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();
                });
            }
        });
    }
});
9
Zack Huston

少し時間を節約できる場合は、わずかな修正を提供します。

  • 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();
         }
      })
    } 
    
1
Derek Mueller

これを少し異なって見ると、バグはブラウザの提案機能が原因であるようです。とにかく私が使用した提案は本当に欲しくないので:

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

よりスムーズなエクスペリエンスを提供します。

1
Ben Trewern