web-dev-qa-db-ja.com

Mobile Safariで仮想キーボードが開いたときに、固定ナビゲーションがこのように移動しないようにするにはどうすればよいですか?

モバイルサファリには固定要素に関する多くのバグがあることを理解していますが、ほとんどの場合、下部の固定ナビゲーションに必要なテキスト入力を追加するまでレイアウトを正しく機能させることができました。ユーザーがテキスト入力要素に焦点を合わせて仮想キーボードが表示されると、ナビゲーションはページの下部に常に固定されますが、ページの中央にある本当に奇妙な場所にジャンプします。

enter image description here

この投稿にコードの一部を追加しますが、どこから始めればいいのかわかりません。そのナビゲーションは下部に固定され、左と下の0、および100%の幅に配置されます。そこから、私は何が起こっているのかわかりません。モバイルサファリのバグであるとしか思えません。

また、テキスト入力要素にフォーカスがあり、仮想キーボードが開いている間のみ、固定された位置を失い、相対的になります。

47
Eric

http://dansajin.com/2012/12/07/fix-position-fixed/ これは提案された解決策の1つです。一撃の価値があるようだ。

つまり、入力がfixededの場合はfocus要素をposition:absoluteに設定し、その要素がblurredの場合はリセットします

.header { 
    position: fixed; 
} 
.footer { 
    position: fixed; 
} 
.fixfixed .header, 
.fixfixed .footer { 
    position: absolute; 
} 

そして

if ('ontouchstart' in window) {
    /* cache dom references */ 
    var $body = $('body'); 

    /* bind events */
    $(document)
    .on('focus', 'input', function() {
        $body.addClass('fixfixed');
    })
    .on('blur', 'input', function() {
        $body.removeClass('fixfixed');
    });
}
19
Sujesh Arukil

一番上の解決策は、問題を解決するためのいくつかの方法ですが、cssクラスを追加するか、modernizを使用すると事態が複雑になると思います。

より単純なソリューションが必要な場合は、non-modernizrnon-extra-css but pure jquery solutionとすべてのプロジェクトでこの修正プログラムを使用するすべてのデバイスとブラウザーで動作します

if ('ontouchstart' in window) {
    $(document).on('focus', 'textarea,input,select', function() {
        $('.navbar.navbar-fixed-top').css('position', 'absolute');
    }).on('blur', 'textarea,input,select', function() {
        $('.navbar.navbar-fixed-top').css('position', '');
    });
}
15
revobtz

私は同様の問題を抱えていましたが、次のcssクラスを入力フォーカスのbody要素に追加し、非フォーカスのときに再び削除することで回避策を見つけました。

.u-oh {
    overflow: hidden;
    height: 100%;
    width: 100%;
    position: fixed;
}
5
sylowgreen

Sylowgreenが行ったことから判断すると、キーはbodyの入力時にinputを修正することです。副<文>この[前述の事実の]結果として、それ故に、従って、だから◆【同】consequently; therefore <文>このような方法で、このようにして、こんなふうに、上に述べたように◆【同】in this manner <文>そのような程度まで<文> AひいてはB◆【用法】A and thus B <文>例えば◆【同】for example; as an example:

$("#myInput").on("focus", function () {
    $("body").css("position", "fixed");
});

$("#myInput").on("blur", function () {
    $("body").css("position", "static");
});
3
Scott Semyan

次のようなjavascriptを追加します。

$(function() {
  var $body;
  if ('ontouchstart' in window) {
    $body = $("body");
    document.addEventListener('focusin', function() {
      return $body.addClass("fixfixed");
    });
    return document.addEventListener('focusout', function() {
      $body.removeClass("fixfixed");
      return setTimeout(function() {
        return $(window).scrollLeft(0);
      }, 20);
    });
  }
});

次のようなクラスを追加します。

.fixfixed header{ 
    position: absolute; 
} 

この記事を参照できます: http://dansajin.com/2012/12/07/fix-position-fixed/

2
wxy112233

このjQueryスクリプトを使用します。

var focus = 0;
var yourInput = $(".yourInputClass");
yourInput.focusin(function(){
    if(!focus) {
        yourInput.blur();
        $("html, body").scrollTop($(document).height());
        focus = 1;
    }
    if(focus) {
        yourInput.focus();
        focus = 0;
    }
});

私にぴったりです。

1
Edie Johnny

focusinイベントとfocusoutイベントは、前の要素がルート要素にバブルアップするため、focusイベントとblurイベントよりもこの問題に適しているようです。 SOで this answer を参照してください。

個人的にはAngularJSを使用しているため、次のように実装しました。

$window.document.body.addEventListener('focusin', function(event) {
    var element = event.target;
    var tagName = element.tagName.toLowerCase();
    if(!$rootScope.inputOverlay && (tagName === 'input' || tagName === 'textarea' || tagName === 'select')) {
        $rootScope.$apply(function() {
            $rootScope.inputOverlay = true;
        });
    }
});
$window.document.body.addEventListener('focusout', function() {
    if($rootScope.inputOverlay) {
        $rootScope.$apply(function() {
            $rootScope.inputOverlay = false;
        });
    }
});

注:これがモバイルSafariの場合、このスクリプトを条件付きで実行しています。

ng-class私のnavbarの属性:

<div class="navbar navbar-default navbar-fixed-top" ng-class="{'navbar-absolute': inputOverlay}">

次のCSSを使用します。

.navbar-absolute {
    position: absolute !important;
}

focusinhere およびfocusouthere について詳しく読むことができます。

1
brain_bacon

上記のソリューションが本当に気に入っています。それを小さなjQueryプラグインにパッケージ化したので、次のことができました。

  • クラスを取得する親を設定します
  • これが適用される要素を設定します(「textarea」と「select」を忘れないでください)。
  • 親クラス名を設定します
  • 連鎖させる
  • 複数回使用できるようにする

コード例:

$.fn.mobileFix = function (options) {
    var $parent = $(this),
    $fixedElements = $(options.fixedElements);

    $(document)
    .on('focus', options.inputElements, function(e) {
        $parent.addClass(options.addClass);
    })
    .on('blur', options.inputElements, function(e) {
        $parent.removeClass(options.addClass);

        // Fix for some scenarios where you need to start scrolling
        setTimeout(function() {
            $(document).scrollTop($(document).scrollTop())
        }, 1);
    });

    return this; // Allowing chaining
};

// Only on touch devices
if (Modernizr.touch) {
    $("body").mobileFix({ // Pass parent to apply to
        inputElements: "input,textarea,select", // Pass activation child elements
        addClass: "fixfixed" // Pass class name
    });
}
1
martinedwards

私のDOMは複雑で、動的な無限スクロールページがあるため、これらのソリューションはどれも役に立ちませんでした。そのため、独自のページを作成する必要がありました。

背景:固定ヘッダーと、ユーザーがその下までスクロールすると、下に固定される要素を使用しています。この要素には検索入力フィールドがあります。さらに、前後スクロール中に動的ページが追加されます。

問題: iOSでは、ユーザーが固定要素の入力をクリックすると、ブラウザーはページの最上部までスクロールします。これは、望ましくない動作を引き起こしただけでなく、ページの上部に動的ページを追加するきっかけにもなりました。

予想される解決策:ユーザーがスティッキー要素の入力をクリックしても、iOSではスクロールしません(まったくなし)。

解決策:

     /*Returns a function, that, as long as it continues to be invoked, will not
    be triggered. The function will be called after it stops being called for
    N milliseconds. If `immediate` is passed, trigger the function on the
    leading Edge, instead of the trailing.*/
    function debounce(func, wait, immediate) {
        var timeout;
        return function () {
            var context = this, args = arguments;
            var later = function () {
                timeout = null;
                if (!immediate) func.apply(context, args);
            };
            var callNow = immediate && !timeout;
            clearTimeout(timeout);
            timeout = setTimeout(later, wait);
            if (callNow) func.apply(context, args);
        };
    };

     function is_iOS() {
        var iDevices = [
          'iPad Simulator',
          'iPhone Simulator',
          'iPod Simulator',
          'iPad',
          'iPhone',
          'iPod'
        ];
        while (iDevices.length) {
            if (navigator.platform === iDevices.pop()) { return true; }
        }
        return false;
    }

    $(document).on("scrollstop", debounce(function () {
        //console.log("Stopped scrolling!");
        if (is_iOS()) {
            var yScrollPos = $(document).scrollTop();
            if (yScrollPos > 200) { //200 here to offset my fixed header (50px) and top banner (150px)
                $('#searchBarDiv').css('position', 'absolute');
                $('#searchBarDiv').css('top', yScrollPos + 50 + 'px'); //50 for fixed header
            }
            else {
                $('#searchBarDiv').css('position', 'inherit');
            }
        }
    },250,true));

    $(document).on("scrollstart", debounce(function () {
        //console.log("Started scrolling!");
        if (is_iOS()) {
            var yScrollPos = $(document).scrollTop();
            if (yScrollPos > 200) { //200 here to offset my fixed header (50px) and top banner (150px)
                $('#searchBarDiv').css('position', 'fixed');
                $('#searchBarDiv').css('width', '100%');
                $('#searchBarDiv').css('top', '50px'); //50 for fixed header
            }
        }
    },250,true));

要件: startsrollおよびstopscroll関数が機能するには、JQuery mobileが必要です。

デバウンスは、スティッキ要素によって作成された遅延を滑らかにするために含まれています。

IOS10でテスト済み。

0
Dima

これをテストしてください。できます。ただテストします。

$(document).on('focus','input', function() {
    setTimeout(function() {
        $('#footer1').css('position', 'absolute');
        $('#header1').css('position', 'absolute');
    }, 0);
});
$(document).on('blur','input', function() {
    setTimeout(function() {
        $('#footer1').css('position', 'fixed');
        $('#header1').css('position', 'fixed');
    }, 800);
});
0
Hesam