カーソルの外側にあるiOS11Safariブートストラップモーダルテキスト領域


85

iOS 11サファリでは、入力テキストボックスカーソルは入力テキストボックスの外側にあります。なぜこの問題が発生しているのかわかりませんでした。ご覧のとおり、フォーカスされたテキストボックスは電子メールのテキスト入力ですが、カーソルはその外側にあります。これはiOS11Safariでのみ発生します

問題


1
これはSafariのバグです。Appleはそれを内部的に修正しましたが、修正はiOSのパブリック(またはベータ)リリースにはまだありません。bugs.webkit.org/show_bug.cgi?id=176896
ビートル

回答:


69

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


6
以下の回答ごとに注意してください-Bootstrapは、モーダルが開いているときに.modal-openをbodyに追加するため、単にpositionを追加できます:そのクラスに固定されています。
timmyc 2017年

1
width:100%本体の幅をデバイスの幅に制限するために追加する必要がある場合もあります。場合によっては、既存のマークアップによっては、それが問題になる可能性があります。また、@ gentleboy(下記)による解決策が気に入っているので、他のブラウザーに問題なくペナルティを課さないようにしています。本体を固定に設定すると、本体が上にスクロールするため、やや面倒です。
Redtopia 2017年

不思議なことに、meteor-cordovaを使用したアプリケーションビルドでこの問題が発生しました。v11 +を実行しているiOSデバイスでこの問題が発生したようです。私の場合、私はすでにposition:fixed申請書の本文に申請していました。代わりにposition:absolutehtml要素でそれを変更し、問題を修正しました。ジェンありがとう!
アダム・ロス・バワーズ

1
これは私たちにとってモーダルフォームの終わりかもしれません。Appleが問題を修正した場合でも、デバイスを更新して作業フォームを確認するのはユーザーの責任です。これを修正するためのより簡単な普遍的な方法はありませんか?ポリフィルはどうですか?
reado 2017

1
あなたは私の人生<3保存
クリスティアンB.

42

個人的には、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>

注意 :javascript関数が自己呼び出しするようになりました


**アップデートiOS11.3-バグ修正😃🎉**

iOS 11.3の時点で、バグは修正されています。以下のためのテストする必要はありませんOS 11_では、iOS11 = /OS 11_0|OS 11_1|OS 11_2/.test(ua);

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

統計1

統計2


2
いいアドバイス。私はこの問題を抱えていませんが、これは答えとしてグローバルかもしれないと思います。ビールが終わったら追加します
micaball 2017年

3
@gentleboy正規表現を使用してOS11を見つけてみませんか?そうすれば、OS 11の各更新をコードに更新する必要がなくなりますか?このようなものiOS11 = /OS 11_(\d{1,2})(_{0,1})(\d{1,2})/.test(us);
T. Evans

1
@RonakK bugs.webkit.orgによると、ベータ11.2および11.3にはまだ存在しているようです
micaball

2
@ T.Evansその正規表現は機能しません。:正しい正規表現は次のようなものかもしれないios11 = /OS 11_(\d{1,2})/.test(ua);
アブラハム

2
固定された位置でも、ドキュメント/本文は上にスクロールします。モーダルオープンの現在のscrollTop位置を取得し、モーダルクローズ後にscrollTop値を読み取ることをお勧めします。このようなjsfiddle.net/im4aLL/hmvget9x/1
ハディ

15

この問題は、Bootstrapだけでなく、Safariだけでもありません。これは、すべてのブラウザで発生するiOS11の完全な表示バグです。上記の修正により、すべてのインスタンスでこの問題が修正されるわけではありません。

バグはここで詳細に報告されます:

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

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


これは私にとっては問題のようで、IOS11にアップデートする前は問題なく動作していました。Androidユーザーには問題はありません。
ハッキングケミスト2017年

11

イライラするバグ、それを特定してくれてありがとう。そうでなければ、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


これが答えになるはずです。Bootstrapは、モーダルが表示されているときにモーダルオープンクラスをボディに追加します。そのクラスをターゲットにする必要があります。
lfkwtz 2017年

1
私はこの問題にしばらく取り組んできました。固定位置を追加するとページがトップに戻るため、このソリューションは私には不十分です。したがって、ユーザーがモーダルを閉じると、スクロール位置が異なります。これはひどいユーザーエクスペリエンスにつながります
ニアポイント2017年

この修正は、モバイルでChromeを使用する際に機能しました。.modal-openがモーダルhtmlに表示されないため、最初は混乱していましたが、とにかくヘッダーにCSSとして追加し、機能しました。
デビッド

4

最も簡単でクリーンなソリューション:

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

1
これが最も簡単な解決策であり、機能しますが、唯一の問題はカーソルが完全に消えることです。初期の状況ほど悪くはありませんが、使い勝手に問題があります。
tmo256 2017年

奇妙なことに、カーソルが消えることはありません
lfkwtz 2017年

1
カーソルが消えるのも経験しましたが、なぜそうなるのか考えてみませんか?
Alex Burgos 2017

4
ええ、最初のフォーカスイベントだけでカーソルが消えていくのも見えます。後続の入力フォーカスでは、カーソルが表示されます。非常に奇妙な。これはiOSのSafariでのみ発生します。
Devin Walker

@DevinWalkerカーソルが消える問題を解決したことはありますか?
付与

3

AppleデバイスをiOS11.3に更新した後、この問題は再現できなくなりました


どういう意味ですか、Appleはそれを修正しましたか?
スタースクリーム2018

1
@Starscreamはい、このソフトウェアバージョン(iOS 11.3)でアップルによって修正されました
Eashan 2018

2

モーダルが開いposition: fixed;ているbodyときに追加します。

$(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>


1
このスレッドの他のソリューションと同様に、モーダルが閉じると、再びトップに戻ります。例:ユーザーはアイテムのグリッドをスクロールし、モーダルで詳細を起動します。この修正により、モーダルを閉じると、再びアイテムのグリッドの一番上に表示され、再スクロールする必要があります
bkwdesign

2
私の
iPhone7

1

を使用したこれらのソリューションposition: fixedとそれに基づく位置修正はscrollTop非常にうまく機能しますが、一部の人々(私を含む)は別の問題を抱えていました:入力がフォーカスされているときにキーボードのキャレット/カーソルが表示されません。

私は、キャレット/カーソルは、我々はときにのみ動作することを観察しないでください使用position: fixedの体に。だから、いくつかのことを試した後、私はこのアプローチを使用してあきらめ、使用することを決めたposition: relative上でbody、使用する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);
});

0

前述のように、style.position propertybodyを設定fixedするとiOS cursor misplacement問題が解決します。

ただし、このゲインは、ページの上部に強制的にスクロールされるという犠牲を伴います。

幸い、この新しいUX問題は、とを活用することでHTMLElement.style、オーバーヘッドをあまりかけずに打ち消すことができますwindow.scrollTo()

基本的な要点はscroll to topbody要素のstyle.topwhenを操作することによってを打ち消すことmountingです。これはYOffsetygap変数によってキャプチャされた値を使用して行われます。

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

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

// 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)

}

これについてのより詳細な例はありますか?モーダルが開いたときに呼び出される関数にマウントがあり、モーダルが閉じているときにディスマウントを関数に入れて呼び出すと思います。
ニールジョーンズ

ああ、うん。意味がわかります。改訂されたソリューションについては、上記を参照してください。また; はい、その意図は、functionsいつmounting、そして、それらを呼び出すことですdismounting。ありがとう。
ArmanCharan18年

-1

誰かがIOS> 11.2で動作し、追加のCSSを必要としないvanillajsの修正を探している場合:

(function() {
    if (!/(iPhone|iPad|iPod).*(OS 11_[0-2]_[0-5])/.test(navigator.userAgent)) return

    document.addEventListener('focusin', function(e) {
        if (!e.target.tagName == 'INPUT' && !e.target.tagName != 'TEXTAREA') return
        var container = getFixedContainer(e.target)
        if (!container) return
        var org_styles = {};
        ['position', 'top', 'height'].forEach(function(key) {
            org_styles[key] = container.style[key]
        })
        toAbsolute(container)
        e.target.addEventListener('blur', function(v) {
            restoreStyles(container, org_styles)
            v.target.removeEventListener(v.type, arguments.callee)
        })
    })

    function toAbsolute(modal) {
        var rect = modal.getBoundingClientRect()
        modal.style.position = 'absolute'
        modal.style.top = (document.body.scrollTop + rect.y) + 'px'
        modal.style.height = (rect.height) + 'px'
    }

    function restoreStyles(modal, styles) {
        for (var key in styles) {
            modal.style[key] = styles[key]
        }
    }

    function getFixedContainer(elem) {
        for (; elem && elem !== document; elem = elem.parentNode) {
            if (window.getComputedStyle(elem).getPropertyValue('position') === 'fixed') return elem
        }
        return null
    }
})()

これは何をしますか:

  1. ブラウザがiOS11.0.0〜11.2.5のSafariであるかどうかを確認します
  2. focusinページ上のイベントを聞く
  3. 集束要素である場合input、またはtextareaとを持つ要素に含まれるfixed位置に容器の位置を変更absoluteに関するながらscrollTopとコンテナ元の寸法。
  4. ぼかしの場合、コンテナの位置をに戻しfixedます。

-1

このソリューションは私にとってはうまくいき、iOS上のすべてのブラウザでうまく機能しました。

.safari-nav-force{
/* Allows content to fill the viewport and go beyond the bottom */
height: 100%;
overflow-y: scroll;
/* To smooth any scrolling behavior */
-webkit-overflow-scrolling: touch;
}

JavsScript

var iOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
$('.modal').on('shown.bs.modal', function () {
    if (iOS && $('.modal').hasClass('in')){
        $('html,body').addClass('safari-nav-force');
    }
});
$('.modal').on('hidden.bs.modal', function () {
    if (iOS && !$('.modal').hasClass('in')){
        $('html,body').removeClass('safari-nav-force');
    }
});


-2

モーダルCSSをオーバーライドし、をpositionからfixedに変更しますabsolute

.modal {
position: absolute !important;
}

1
私のシナリオでは機能しませんでした。固定を絶対に変更すると、多くのノックオン効果が発生する可能性があります
Steve D

@ SteveD-それを機能させるには、モーダルを<body>に追加する必要があります。そして、<body>には--position:relativeが必要です。そしてそれが機能するはずのとき:)
ダン

-3

#modal position:absoluteに追加して、positionに関連する将来の問題を修正します:fixed


あなたの答えは完全に重複しています。重複する回答を投稿しないように注意してください。
mechMK1 2017
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.