web-dev-qa-db-ja.com

iOS 11 Safariブートストラップモーダルテキスト領域(カーソルの外側)

IOS 11サファリでは、入力テキストボックスカーソルは入力テキストボックスの外側にあります。なぜそれがこの問題を抱えているのかわかりませんでした。ご覧のとおり、私の注目するテキストボックスは電子メールによるテキスト入力ですが、カーソルはその外側にあります。これはiOS 11 Safariでのみ起こります

Problem

81
kekkeme

モーダルを開くときにボディにposition:fixedを追加することで問題を解決しました。これがお役に立てば幸いです。

個人的にはposition: fixed自動的に上にスクロールする。かなり面倒です!

他のデバイスやバージョンへの不利益を避けるため私はこの修正を適切なiOSのバージョンにのみ適用します。


**バージョン1 - すべてのモードの修正**

javascript/jQueryの場合

$(document).ready(function() {

    // Detect ios 11_x_x affected  
    // NEED TO BE UPDATED if new versions are affected
    var ua = navigator.userAgent,
    iOS = /iPad|iPhone|iPod/.test(ua),
    iOS11 = /OS 11_0|OS 11_1|OS 11_2/.test(ua);

    // ios 11 bug caret position
    if ( iOS && iOS11 ) {

        // Add CSS class to body
        $("body").addClass("iosBugFixCaret");

    }

});

CSS用

/* Apply CSS to iOS affected versions only */
body.iosBugFixCaret.modal-open { position: fixed; width: 100%; }

**バージョン2 - 選択されたモーダルのみ**

クラス.inputModalを使って、選択したモーダルに対してのみ起動するように関数を修正しました。

一番上にスクロールしないようにするには、入力を持つモーダルだけに影響を与えます。

javascript/jQueryの場合

$(document).ready(function() {

    // Detect ios 11_x_x affected
    // NEED TO BE UPDATED if new versions are affected 
    (function iOS_CaretBug() {

        var ua = navigator.userAgent,
        scrollTopPosition,
        iOS = /iPad|iPhone|iPod/.test(ua),
        iOS11 = /OS 11_0|OS 11_1|OS 11_2/.test(ua);

        // ios 11 bug caret position
        if ( iOS && iOS11 ) {

            $(document.body).on('show.bs.modal', function(e) {
                if ( $(e.target).hasClass('inputModal') ) {
                    // Get scroll position before moving top
                    scrollTopPosition = $(document).scrollTop();

                    // Add CSS to body "position: fixed"
                    $("body").addClass("iosBugFixCaret");
                }
            });

            $(document.body).on('hide.bs.modal', function(e) {
                if ( $(e.target).hasClass('inputModal') ) {         
                    // Remove CSS to body "position: fixed"
                    $("body").removeClass("iosBugFixCaret");

                    //Go back to initial position in document
                    $(document).scrollTop(scrollTopPosition);
                }
            });

        }
    })();
});

CSS用

/* Apply CSS to iOS affected versions only */
body.iosBugFixCaret.modal-open { position: fixed; width: 100%; }

HTMLの場合クラスinputModalをモーダルに追加します

<div class="modal fade inputModal" tabindex="-1" role="dialog">
    ...
</div>

Nota bene javascript関数は現在自己起動しています


**アップデートiOS 11.3 - バグが修正されました???????? **

IOS 11.3以降、このバグは修正されています。 iOS11 = /OS 11_0|OS 11_1|OS 11_2/.test(ua);OS 11_をテストする必要はありません。

iOS 11.2はまだ広く使用されているので({2018年4月現在)ただし注意してください。見る

統計1

統計2

42
micaball

この問題はBootstrapを超え、Safariだけではありません。これはiOS 11の全画面表示のバグで、すべてのブラウザで発生します。上記の修正では、すべての場合にこの問題が解決されるわけではありません。

このバグはここで詳細に報告されています。

https://medium.com/@eirik.luka/how-to-fix-the-ios-11-input-element-in-fixed-modals-bug-aaf66c7ba3f8

おそらく彼らはすでにそれをバグとしてAppleに報告していたのでしょう。

15
Eric Shawn

イライラするバグ、識別してくれてありがとう。そうでなければ、私は壁に私のiPhoneや私の頭を叩いているでしょう。

最も簡単な修正は(1行のコード変更)です。

次のCSSをHTMLまたは外部のCSSファイルに追加するだけです。

<style type="text/css">
.modal-open { position: fixed; }
</style>

これが完全に機能する例です。

.modal-open { position: fixed; }
<link href="https://getbootstrap.com/docs/3.3/dist/css/bootstrap.min.css" rel="stylesheet">

<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exampleModal" data-whatever="@mdo">Open modal for @mdo</button>
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exampleModal" data-whatever="@fat">Open modal for @fat</button>
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exampleModal" data-whatever="@getbootstrap">Open modal for @getbootstrap</button>
...more buttons...

<div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
        <h4 class="modal-title" id="exampleModalLabel">New message</h4>
      </div>
      <div class="modal-body">
        <form>
          <div class="form-group">
            <label for="recipient-name" class="control-label">Recipient:</label>
            <input type="text" class="form-control" id="recipient-name">
          </div>
          <div class="form-group">
            <label for="message-text" class="control-label">Message:</label>
            <textarea class="form-control" id="message-text"></textarea>
          </div>
        </form>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
        <button type="button" class="btn btn-primary">Send message</button>
      </div>
    </div>
  </div>
</div>

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
    <script src="https://getbootstrap.com/docs/3.3/dist/js/bootstrap.min.js"></script>

私はここに問題を提出しました: https://github.com/twbs/bootstrap/issues/24059

11

最も簡単でクリーンな解決策:

body.modal-open { position: fixed; width: 100%; }
4
lfkwtz

この問題は、AppleデバイスをiOS 11.3にアップデートした後では再現できなくなります。

3
Eashan

モーダルが開いているときは、bodyposition: fixed;を追加します。

$(document).ready(function($){
    $("#myBtn").click(function(){
        $("#myModal").modal("show");
    });
    $("#myModal").on('show.bs.modal', function () {
        $('body').addClass('body-fixed');
    });
    $("#myModal").on('hide.bs.modal', function () {
        $('body').removeClass('body-fixed');
    });
});
.body-fixed {
    position: fixed;
    width: 100%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/Twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>

<button type="button" class="btn btn-info btn-lg" id="myBtn">Open Modal</button>

<!-- Modal -->
<div class="modal fade" id="myModal" role="dialog">
        <div class="modal-dialog">
                <div class="modal-content">
                        <div class="modal-header">
                                <button type="button" class="close" data-dismiss="modal">&times;</button>
                                <h4 class="modal-title">Form</h4>
                        </div>
                        <div class="modal-body">
                                <div class="form-group">
                                        <label class="control-label">Input #1</label>
                                        <input type="text" class="form-control">
                                </div>
                                <div class="form-group">
                                        <label class="control-label">Input #2</label>
                                        <input type="text" class="form-control">
                                </div>
                                <div class="form-group">
                                        <label class="control-label">Input #3</label>
                                        <input type="text" class="form-control">
                                </div>
                                <div class="form-group">
                                        <label class="control-label">Input #4</label>
                                        <input type="text" class="form-control">
                                </div>
                        </div>
                        <div class="modal-footer">
                                <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
                        </div>
                </div>
        </div>
</div>
2
Anuruk S.

position: fixedscrollTopに基づく位置補正を使ったこれらの解決策は本当にうまくいきますが、私を含めて何人かの人々は別の問題を抱えています:.

キャレット/カーソルは、 DON'T がボディにposition: fixedを使用している場合にのみ機能することを確認しました。そこで、いくつか試してみた結果、このアプローチの使用をあきらめ、代わりにbodyposition: relativeを使用し、代わりにscrollTopを使用して モーダルの最上位位置 を決定しました。

以下のコードを参照してください。

var iosScrollPosition = 0;

function isIOS() {
   // use any implementation to return true if device is iOS
}

function initModalFixIOS() {
    if (isIOS()) {
        // Bootstrap's fade animation does not work with this approach
        // iOS users won't benefit from animation but everything else should work
        jQuery('#myModal').removeClass('fade');
    }
}

function onShowModalFixIOS() {
    if (isIOS()) {
        iosScrollPosition = jQuery(window).scrollTop();
        jQuery('body').css({
            'position': 'relative', // body is now relative
            'top': 0
        });
        jQuery('#myModal').css({
            'position': 'absolute', // modal is now absolute
            'height': '100%',
            'top': iosScrollPosition // modal position correction
        });
        jQuery('html, body').css('overflow', 'hidden'); // prevent page scroll
    }
}

function onHideModalFixIOS() {
    // Restore everything
    if (isIOS()) {
        jQuery('body').css({
            'position': '',
            'top': ''
        });
        jQuery('html, body').scrollTop(iosScrollPosition);
        jQuery('html, body').css('overflow', '');
    }
}

jQuery(document).ready(function() {
    initModalFixIOS();
    jQuery('#myModal')
        .on('show.bs.modal', onShowModalFixIOS)
        .on('hide.bs.modal', onHideModalFixIOS);
});
1
FlavioEscobar

前述のとおり、propertystyle.positionbodyfixedに設定すると、iOS cursor misplacementの問題は解決します。

ただし、この利点は、ページの先頭に強制的にスクロールされることを犠牲にしています。

幸い、 HTMLElement.style および window.scrollTo() を利用することで、この新しいUXの問題をあまり多くのオーバーヘッドなしに打ち消すことができます。

基本的な要旨は、bodyのときにmounting要素のscroll to topを操作することによってstyle.topを打ち消すことです。これは、YOffset変数によって取得されたygap値を使用して行われます。

そこからは、単にbody'sstyle.top0にリセットし、dismountingのときにwindow.scrollTo(0, ygap)を使用してユーザーのビューをリフレーミングするだけです。

実際的な例については以下を参照してください。

// Global Variables (Manage Globally In Scope).
const body = document.querySelector('body') // Body.
let ygap = 0 // Y Offset.


// On Mount (Call When Mounting).
const onModalMount = () => {

  // Y Gap.
  ygap = window.pageYOffset || document.documentElement.scrollTop

  // Fix Body.
  body.style.position = 'fixed'

  // Apply Y Offset To Body Top.
  body.style.top = `${-ygap}px`

}


// On Dismount (Call When Dismounting).
const onModalDismount = () => {

  // Unfix Body.
  body.style.position = 'relative'

  // Reset Top Offset.
  body.style.top = '0'

  // Reset Scroll.
  window.scrollTo(0, ygap)

}
0
Arman Charan