iOS 11 Safari引导模式文本区域位于游标外部

时间:2017-09-21 08:31:21

标签: html ios bootstrap-modal mobile-safari ios11

使用iOS 11 safari,输入文本框光标位于输入文本框之外。我们不明白为什么会遇到这个问题。正如您所看到的,我的焦点文本框是电子邮件文本输入,但我的光标在它之外。这仅适用于iOS 11 Safari

Problem

15 个答案:

答案 0 :(得分:68)

我在打开模态时通过向正文添加position:fixed来修复此问题。 希望这会对你有所帮助。

答案 1 :(得分: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>

Nota bene javascript函数现在是自我调用的

**更新iOS 11.3 - 错误更正**

自iOS 11.3起,该错误已得到纠正。无需在OS 11_

中测试iOS11 = /OS 11_0|OS 11_1|OS 11_2/.test(ua);

但要小心,因为iOS 11.2仍然被广泛使用(截至2018年4月)。参见

stat 1

stat 2

答案 2 :(得分:15)

这个问题超越了Bootstrap,而不仅仅是Safari。这是iOS 11中的完整显示错误,在所有浏览器中都会出现。上述修复程序并未解决此问题。

此处详细报告了该错误:

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

据说他们已经向苹果报告了这个错误。

答案 3 :(得分: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

答案 4 :(得分:4)

最简单/最干净的解决方案:

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

答案 5 :(得分:3)

将Apple设备更新后,此问题不再可重现  iOS 11.3

答案 6 :(得分:2)

当模态打开时,将position: fixed;添加到body

&#13;
&#13;
$(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');
    });
});
&#13;
.body-fixed {
    position: fixed;
    width: 100%;
}
&#13;
<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>
&#13;
&#13;
&#13;

答案 7 :(得分:1)

那些使用position: fixed的解决方案和基于scrollTop的位置修正工作得非常好,但是有些人(包括我)还有另一个问题:键盘插入符/光标在输入被聚焦时没有显示。

我观察到插入/光标只有在我们 DON&#39; 在身体上使用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);
});

答案 8 :(得分:0)

如前所述:将style.position的{​​{1}} property设置为body可解决fixed问题。

然而,这种增益是以强行滚动到页面顶部为代价的。

幸运的是,利用HTMLElement.stylewindow.scrollTo()可以消除这个新的iOS cursor misplacement问题而不会产生太多开销。

基本要点是在UX时通过操纵scroll to top元素body来抵消style.top。这是使用mounting变量捕获的YOffset值完成的。

从那里,只需将ygap body's重置为style.top并在{0时使用window.scrollTo(0, ygap)重新构建用户的视图1}}。

请参阅下面的实例。

dismounting

答案 9 :(得分:-1)

任何人都在寻找适用于IOS&gt; 11.2并且不需要任何其他CSS的vanilla js中的修复程序:

(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. 检查浏览器是否为iOS 11.0.0上的Safari - 11.2.5
  2. 收听页面上的focusin个活动
  3. 如果焦点元素是inputtextarea且包含在fixed位置的元素中,请将容器位置更改为absolute,同时考虑{{1}容器原始尺寸。
  4. 在模糊时,将容器的位置恢复为scrollTop

答案 10 :(得分:-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');
    }
});

答案 11 :(得分:-2)

您是否尝试 viewport-fit = cover 进行元视口。

看看这个:https://ayogo.com/blog/ios11-viewport/

答案 12 :(得分:-2)

覆盖模态css并将其positionfixed更改为absolute

.modal {
position: absolute !important;
}

答案 13 :(得分:-3)

添加到#modal位置:绝对修复与位置相关的未来问题:已修复

答案 14 :(得分:-8)

enter image description here

对于这类问题,我们发现了以下3个解决方案

1)将容器从position: fixed;更改为position: absolute;。这样做的缺点是,用户可以轻松地从我们想要占用窗口房地产的模式中滚动出来。

2)你可能会认为模态在较小的屏幕上不起作用,最好的解决方法是根本不使用模态,但在我们的情况下这将是一个很大的重写,我们需要修复尽快出去。

3)我们发现在我们的情况下最好的解决方案是保持模态固定,但要将其拉伸到窗口的边缘,用display: none;将其余内容隐藏在体内。这样可以消除身高高于视口的问题,并且在关注输入时不会有背景滚动。

了解更多详情here

上面提到的链接你将得到bug的状态,即它是否从iPhone方面解决