在 iOS 11 Safari 中,输入文本框光标位于输入文本框之外。我们不明白为什么会出现这个问题。如您所见,我的重点文本框是电子邮件文本输入,但我的光标在它之外。这只发生在 iOS 11 Safari 上
https://i.stack.imgur.com/34d6d.png
我通过在打开模式时将 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 添加到 modal
<div class="modal fade inputModal" tabindex="-1" role="dialog">
...
</div>
注意 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 月)。看
iOS11 = /OS 11_(\d{1,2})(_{0,1})(\d{1,2})/.test(us);
ios11 = /OS 11_(\d{1,2})/.test(ua);
这个问题不仅限于 Bootstrap,也不仅仅是 Safari。这是 iOS 11 中所有浏览器中出现的一个完整显示错误。上述修复并未在所有情况下都解决此问题。
该错误在此处详细报告:
https://medium.com/@eirik.luka/how-to-fix-the-ios-11-input-element-in-fixed-modals-bug-aaf66c7ba3f8
据说他们已经将它作为一个错误报告给了苹果。
令人沮丧的错误,感谢您识别它。否则,我会把我的 iPhone 或头撞到墙上。
最简单的解决方法是(更改 1 行代码):
只需将以下 CSS 添加到 html 或外部 css 文件。
<style type="text/css">
.modal-open { position: fixed; }
</style>
这是一个完整的工作示例:
.modal-open { 位置:固定; } ...更多按钮...
我在这里提交了一个问题:https://github.com/twbs/bootstrap/issues/24059
最简单/最干净的解决方案:
body.modal-open { position: fixed; width: 100%; }
将您的苹果设备更新到 iOS 11.3 后,此问题不再重现
模式打开时将 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 { 位置:固定;宽度:100%; } < !-- 模态 -->
那些使用 position: fixed
和基于 scrollTop
的位置校正的解决方案非常有效,但有些人(包括我)遇到了另一个问题:键盘插入符号/光标在输入聚焦时不显示。
我观察到插入符号/光标仅在我们不要在正文上使用 position: fixed
时才有效。所以在尝试了几件事之后,我放弃了使用这种方法,并决定在 body
上使用 position: relative
并使用 scrollTop
来纠正 modal 的顶部位置。
请参见下面的代码:
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);
});
如前所述:将 body
的 style.position
property
设置为 fixed
解决了 iOS cursor misplacement
问题。
然而,这种收益是以被强制滚动到页面顶部为代价的。
幸运的是,可以通过利用 HTMLElement.style
和 window.scrollTo()
来消除这个新的 UX
问题而无需太多开销。
基本要点是通过在 mounting
时操作 body
元素的 style.top
来抵消 scroll to top
。这是使用 ygap
变量捕获的 YOffset
值完成的。
从那里只需将 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)
}
mounting
和 dismounting
时调用那些 functions
。谢谢。
如果有人正在寻找适用于 IOS >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
}
})()
这是做什么的:
检查浏览器是否是 iOS 11.0.0 - 11.2.5 上的 Safari 监听页面上的任何 focusin 事件如果焦点元素是输入或文本区域并且包含在具有固定位置的元素中,则将容器位置更改为绝对位置关于 scrollTop 和容器的原始尺寸。在模糊时,将容器的位置恢复为固定。
这个解决方案对我有用,并且它在 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');
}
});
覆盖模态 css 并将其 position
从 fixed
更改为 absolute
.modal {
position: absolute !important;
}
添加到#modal 位置:绝对它修复与位置相关的未来问题:已修复
width:100%
以将主体宽度限制为设备宽度。在某些情况下,根据现有的标记,这可能是一个问题。我也喜欢@gentleboy(下)的解决方案,以免在没有问题的情况下惩罚其他浏览器,因为当将正文设置为固定时会导致正文滚动到顶部,这有点烦人。position:fixed
应用于应用程序的主体。相反,我在html
元素上将其更改为position:absolute
并解决了我的问题。谢谢珍!