IOS 11サファリでは、入力テキストボックスカーソルは入力テキストボックスの外側にあります。なぜそれがこの問題を抱えているのかわかりませんでした。ご覧のとおり、私の注目するテキストボックスは電子メールによるテキスト入力ですが、カーソルはその外側にあります。これはiOS 11 Safariでのみ起こります
モーダルを開くときにボディにposition:fixed
を追加することで問題を解決しました。これがお役に立てば幸いです。
個人的にはposition: fixed
自動的に上にスクロールする。かなり面倒です!
他のデバイスやバージョンへの不利益を避けるため私はこの修正を適切なiOSのバージョンにのみ適用します。
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%; }
クラス.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以降、このバグは修正されています。 iOS11 = /OS 11_0|OS 11_1|OS 11_2/.test(ua);
でOS 11_
をテストする必要はありません。
iOS 11.2はまだ広く使用されているので({2018年4月現在)ただし注意してください。見る
この問題はBootstrapを超え、Safariだけではありません。これはiOS 11の全画面表示のバグで、すべてのブラウザで発生します。上記の修正では、すべての場合にこの問題が解決されるわけではありません。
このバグはここで詳細に報告されています。
https://medium.com/@eirik.luka/how-to-fix-the-ios-11-input-element-in-fixed-modals-bug-aaf66c7ba3f8
おそらく彼らはすでにそれをバグとしてAppleに報告していたのでしょう。
イライラするバグ、識別してくれてありがとう。そうでなければ、私は壁に私の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">×</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
最も簡単でクリーンな解決策:
body.modal-open { position: fixed; width: 100%; }
この問題は、AppleデバイスをiOS 11.3にアップデートした後では再現できなくなります。
モーダルが開いているときは、body
にposition: 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">×</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>
position: fixed
とscrollTop
に基づく位置補正を使ったこれらの解決策は本当にうまくいきますが、私を含めて何人かの人々は別の問題を抱えています:.
キャレット/カーソルは、 DON'T がボディにposition: fixed
を使用している場合にのみ機能することを確認しました。そこで、いくつか試してみた結果、このアプローチの使用をあきらめ、代わりにbody
にposition: 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);
});
前述のとおり、property
のstyle.position
body
をfixed
に設定すると、iOS cursor misplacement
の問題は解決します。
ただし、この利点は、ページの先頭に強制的にスクロールされることを犠牲にしています。
幸い、 HTMLElement.style
および window.scrollTo()
を利用することで、この新しいUX
の問題をあまり多くのオーバーヘッドなしに打ち消すことができます。
基本的な要旨は、body
のときにmounting
要素のscroll to top
を操作することによってstyle.top
を打ち消すことです。これは、YOffset
変数によって取得されたygap
値を使用して行われます。
そこからは、単にbody's
をstyle.top
に0
にリセットし、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)
}