光标外部的iOS 11 Safari引导模式文本区域


85

使用iOS 11野生动物园时,输入文本框光标在输入文本框之外。我们不明白为什么会有这个问题。如您所见,我的焦点文本框是电子邮件文本输入,但光标不在文本框内。这仅在iOS 11 Safari中发生

问题


1
这是Safari的错误。Apple已在内部对其进行了修复,但尚未在iOS的公开(甚至Beta)版本中进行修复。bugs.webkit.org/show_bug.cgi?id=176896
甲虫

Answers:


69

我通过position:fixed在打开模态时添加到主体来解决此问题。希望这会帮助你。


6
请注意以下每个答案-当模式打开时,Bootstrap将.modal-open添加到主体,因此您可以简单地添加position:固定到该类。
timmyc

1
您可能还需要添加width:100%以将主体宽度限制为设备宽度。在某些情况下,取决于现有的标记,这可能是一个问题。我也喜欢@gentleboy(下)的解决方案,以免对其他浏览器没有问题,因为将主体设置为固定会导致主体滚动到顶部,这有点烦人。
Redtopia '17

奇怪的是,我在使用meteor-cordova构建应用程序时遇到了这个问题。似乎所有运行v11 +的iOS设备都存在此问题。就我而言,我已经position:fixed申请了该申请的主体。相反,我将其更改position:absolutehtml元素,并解决了我的问题。谢谢仁!
亚当·罗斯·鲍尔斯

1
对我们来说,这可能是情态形式的终结。即使Apple解决了该问题,用户还是可以自行决定更新设备以查看工作表。有没有更简单的通用方法来解决此问题?多边形填充呢?
Reado

1
您拯救了我的生命<3
Cristian 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>

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月)。看到

统计1

统计2


2
好的建议。我没有这个问题,但我想这可能是全球性的答案。我

3
@gentleboy为什么不使用REGEX查找任何OS 11?这样一来,您不必将每个OS 11更新都更新为您的代码?像这样的事情iOS11 = /OS 11_(\d{1,2})(_{0,1})(\d{1,2})/.test(us);
T. Evans

1
@RonakK看起来它仍然存在于测试11.2和11.3根据bugs.webkit.org
micaball

2
@ T.Evans正则表达式不起作用。正确的正则表达式可能是这样的:ios11 = /OS 11_(\d{1,2})/.test(ua);
Abraham

2
固定位置仍将文档/正文滚动到顶部。我建议在模式打开时获取当前的scrollTop位置,并在模式关闭后读取scrollTop值。像这样jsfiddle.net/im4aLL/hmvget9x/1
1

15

这个问题不仅限于Bootstrap,而且不仅仅限于Safari。这是所有浏览器中出现的iOS 11中的完整显示错误。上面的修复程序不能在所有情况下都解决此问题。

该错误的详细报告如下:

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

据说他们已经将它作为错误报告给了Apple。


对我来说,这似乎是个问题,在更新到IOS 11之前运行正常。Android用户没有问题。
hackingchemist

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

1
我处理这个问题已有一段时间了。对于我来说,此解决方案是不够的,因为固定添加位置会将页面滚动回到顶部。因此,当用户关闭模式时,它们将处于不同的滚动位置。这会带来可怕的用户体验
Nearpoint,2015年

此修复程序对我在移动设备上使用Chrome很有用。一开始很困惑,因为.modal-open不会出现在模态html中,但是无论如何我还是将其作为CSS添加到了标题中,并且可以正常工作。
大卫

4

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

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

1
这是最简单的解决方案,并且可行,但是唯一的问题是光标完全消失了。它不像最初的情况那样糟糕,但是存在可用性问题。
tmo256 '17

很奇怪,我还没有遇到过消失的光标
lfkwtz

1
我也经历了光标的消失,对为什么会发生这种情况有任何想法吗?
亚历克斯·布尔戈斯

4
是的,我也看到第一个焦点事件的光标消失了。后续输入焦点使光标出现。很奇怪。这仅在iOS上的Safari中发生。
Devin Walker

@DevinWalker你们曾经解决过消失的光标问题吗?
授予

3

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


Apple固定它是什么意思?
红蜘蛛

1
@Starscream是的,它已由苹果使用此软件版本(iOS 11.3)
修复-Eashan

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
在我的iPhone 7 plus上,此修复导致我的光标完全消失
bkwdesign

1

这些position: fixed基于使用和位置校正的解决方案scrollTop确实能很好地工作,但是某些人(包括我在内)遇到了另一个问题:键盘插入符/光标在输入集中时未显示。

我观察到插入符/光标仅在我们不对position: fixed身体使用时才起作用。尝试几件事情之后所以,我放弃了使用这种方法,并决定使用position: relativebody和使用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 propertybodyfixed的解决了iOS cursor misplacement问题。

但是,这种获得是以强制滚动到页面顶部为代价的。

幸运的是,UX通过利用HTMLElement.style和,可以在没有太多开销的情况下解决这个新问题window.scrollTo()

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

从那里开始,只需body's style.top要将重置为,0并使用window.scrollTo(0, ygap)when来重新定义用户的视图即可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)

}

您是否有更详细的示例?我猜想我会在模式打开时调用Mount函数,然后将Dismount放在函数中并在模式关闭时调用。
尼尔·琼斯,

是的。我明白你的意思了。请参阅上面的修订解决方案。也; 是的,目的是让您functionsmounting和时打电话给他们dismounting。谢谢。
Arman Charan

-1

如果有人在Vanilla js中寻找可在IOS> 11.2上运行并且不需要任何其他CSS的修复程序,则:

(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-11.2.5上的Safari
  2. 监听focusin页面上的所有事件
  3. 如果聚焦元素是ainput或atextarea并且包含在具有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从更改fixedabsolute

.modal {
position: absolute !important;
}

1
在我的情况下不起作用。将固定值更改为绝对值会产生很多效果
Steve D

@SteveD-要使其工作,您应该将模态附加到<body>。并且<body>应该具有-position:relative。以及何时应该起作用:)

-3

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


您的答案是完全重复的。请确保不要发布重复的答案。
MechMK1
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.