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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/46339063/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-29 14:55:27  来源:igfitidea点击:

iOS 11 Safari bootstrap modal text area outside of cursor

htmliosbootstrap-modalmobile-safariios11

提问by kekkeme

With iOS 11 safari, input textbox cursor are outside of input textbox. We did not get why it is having this problem. As you can see my focused text box is email text input but my cursor is outside of it. This only happens with iOS 11 Safari

在 iOS 11 safari 中,输入文本框光标位于输入文本框之外。我们不明白为什么它会出现这个问题。正如你所看到的,我的焦点文本框是电子邮件文本输入,但我的光标在它之外。这只发生在 iOS 11 Safari

Problem

问题

采纳答案by Nattawat Tarweesripayap

I fixed the issue by adding position:fixedto the body when opening a modal. Hope this will help you.

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

回答by micaball

Personally, position: fixedscroll to top automatically. Quite annoying !

就个人而言,position: fixed自动滚动到顶部。很烦人!

To avoid penalizing other devices and versionsI apply this fix only to the appropriate versions of iOS.

为避免惩罚其他设备和版本,我仅将此修复程序应用于相应版本的 iOS。



**VERSION 1 - All modals fix**

**版本 1 - 所有模态修复**

For the javascript/jQuery

对于 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");

    }

});

For the CSS

对于 CSS

/* Apply CSS to iOS affected versions only */
body.iosBugFixCaret.modal-open { position: fixed; width: 100%; }


**VERSION 2 - Selected modals only**

**版本 2 - 仅选定的模态**

I modified the function to fire only for selected modals with a class .inputModal

我修改了函数以仅针对具有类的选定模态触发 .inputModal

Only the modals with inputs should be impacted to avoid the scroll to top.

只有带有输入的模态才会受到影响,以避免滚动到顶部。

For the javascript/jQuery

对于 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);
                }
            });

        }
    })();
});

For the CSS

对于 CSS

/* Apply CSS to iOS affected versions only */
body.iosBugFixCaret.modal-open { position: fixed; width: 100%; }

For the HTMLAdd the class inputModalto the modal

对于 HTML将类inputModal添加到模态

<div class="modal fade inputModal" tabindex="-1" role="dialog">
    ...
</div>

Nota beneThe javascript function is now self-invoking

注意javascript 函数现在是自调用的



**UPDATE iOS 11.3 - Bug corrected **

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

As of iOS 11.3, the bug has been corrected. There is no need to test for OS 11_in iOS11 = /OS 11_0|OS 11_1|OS 11_2/.test(ua);

从 iOS 11.3 开始,该错误已得到纠正。有没有需要测试OS 11_iOS11 = /OS 11_0|OS 11_1|OS 11_2/.test(ua);

But be carefulas iOS 11.2 is still widely used (as of April 2018). See

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

stat 1

状态 1

stat 2

状态 2

回答by Eric Shawn

This issue goes beyond Bootstrap, and beyond just Safari. It is a full display bug in iOS 11 that occurs in all browsers. The fix above does not fix this issue in all instances.

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

The bug is reported in detail here:

该错误在此处详细报告:

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

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

Supposedly they already reported it to Apple as a bug.

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

回答by Scott David Murphy

Frustrating bug, thanks for identifying it. Otherwise, I would be banging my iphone or my head against the wall.

令人沮丧的错误,感谢您识别它。否则,我会用我的 iphone 或我的头撞墙。

The simplest fix is (1 line of code change):

最简单的解决方法是(更改 1 行代码):

Just add the following CSS to the html or to an external css file.

只需将以下 CSS 添加到 html 或外部 css 文件。

<style type="text/css">
.modal-open { position: fixed; }
</style>

Here is a full working example:

这是一个完整的工作示例:

.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>

I submitted an issue here: https://github.com/twbs/bootstrap/issues/24059

我在这里提交了一个问题:https: //github.com/twbs/bootstrap/issues/24059

回答by lfkwtz

Easiest/cleanest solution:

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

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

回答by Eashan

This issue is no longer reproducible after updating your apple devices to iOS 11.3

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

回答by Anuruk S.

Add position: fixed;to bodywhen modal is open.

添加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>

回答by FlavioEscobar

Those solutions using position: fixedand position correction based on scrollTopwork really well, but some people (including me) got another issue: keyboard caret/cursor not showing when inputs are focused.

那些position: fixed基于scrollTop工作的使用和位置校正的解决方案非常好,但有些人(包括我)遇到了另一个问题:键盘插入符号/光标在输入集中时不显示。

I observed that caret/cursor works only when we DON'Tuse position: fixedon body. So after trying several things, I gave up on using this approach and decided to use position: relativeon bodyand use scrollTopto correct modal's top positioninstead.

我观察到插入符号/光标仅在我们不在position: fixed身体上使用时才起作用。所以在尝试了几件事之后,我放弃了使用这种方法,并决定使用position: relativeonbody和 usescrollTop来纠正模态的顶部位置

See code below:

见下面的代码:

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);
});

回答by Arman Charan

As previously mentioned: setting the style.positionpropertyof bodyto fixedsolves the iOS cursor misplacementissue.

如前所述:设置style.positionpropertyofbodyfixed解决iOS cursor misplacement问题。

However, this gain comes at the cost of being forcibly scrolled to the top of the page.

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

Fortunately, this new UXproblem can be negated without much overhead by leveraging HTMLElement.styleand window.scrollTo().

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

The basic gist is to counteract the scroll to topby manipulating the bodyelement's style.topwhen mounting. This is done using the YOffsetvalue captured by the ygapvariable.

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

From there it's simply a matter of resetting the body'sstyle.topto 0and reframing the user's view using window.scrollTo(0, ygap)when dismounting.

从那里开始,只需使用when将body'sstyle.topto重置为0并重新构建用户视图即可。window.scrollTo(0, ygap)dismounting

See below for a practical example.

请参阅下面的实际示例。

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

}

回答by Manuel Otto

Incase anyone is looking for a fix in vanilla js that works on IOS >11.2 and doesnt require any additional CSS:

如果有人正在寻找适用于 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
    }
})()

What this does is:

它的作用是:

  1. Check if the browser is Safari on iOS 11.0.0 - 11.2.5
  2. Listen for any focusinevents on the page
  3. If the focused element is an inputor a textareaand is contained in an element with fixedposition, change the container position to absolutewhile regarding scrollTopand the containers original dimensions.
  4. On blur, restore the container's position to fixed.
  1. 检查浏览器是否为 iOS 11.0.0 - 11.2.5 上的 Safari
  2. 侦听focusin页面上的任何事件
  3. 如果焦点元素是 aninput或 atextarea并且包含在具有fixed位置的元素中,则将容器位置更改为absolutewhilescrollTop和容器的原始尺寸。
  4. 在模糊时,将容器的位置恢复到fixed