iOS 11 Safari 부트 스트랩 모달 텍스트 영역이 커서 외부에 있음


85

iOS 11 safari에서는 입력 텍스트 상자 커서가 입력 텍스트 상자 밖에 있습니다. 왜이 문제가 발생하는지 이해하지 못했습니다. 보시다시피 내 집중된 텍스트 상자는 이메일 텍스트 입력이지만 커서는 그 밖에 있습니다. 이것은 iOS 11 Safari에서만 발생합니다.

문제


1
이것은 Safari의 버그입니다. Apple은 내부적으로 수정했지만 아직 iOS의 공개 (또는 베타) 릴리스가 아닙니다. bugs.webkit.org/show_bug.cgi?id=176896
Beetle

답변:


69

position:fixed모달을 열 때 본체 에 추가하여 문제를 해결했습니다 . 이것이 당신을 도울 수 있기를 바랍니다.


6
아래 답변에 대한 참고 사항-Bootstrap은 모달이 열려있을 때 body에 .modal-open을 추가하므로 간단히 position : fixed를 해당 클래스에 추가 할 수 있습니다.
timmyc

1
width:100%본체 너비를 장치 너비로 제한 하기 위해 추가해야 할 수도 있습니다 . 경우에 따라 기존 마크 업에 따라 문제가 될 수 있습니다. 나는 또한 @gentleboy (아래)의 솔루션을 좋아하여 문제없이 다른 브라우저에 불이익을주지 않기 위해 본문을 고정으로 설정하면 본문이 위쪽으로 스크롤되므로 다소 짜증이납니다.
Redtopia

이상하게도 meteor-cordova로 빌드 한 애플리케이션에서이 문제가 발생했습니다. v11 +를 실행하는 모든 iOS 기기에이 문제가있는 것 같습니다. 제 경우에는 이미 position:fixed신청서 본문에 신청했습니다. 대신 요소 position:absolute에서 변경하고 html내 문제를 해결했습니다. Jen 감사합니다!
Adam Ross Bowers

1
이것은 우리에게 모달 형식의 끝이 될 수 있습니다. Apple이 문제를 해결하더라도 작동 양식을보기 위해 장치를 업데이트하는 것은 사용자에게 달려 있습니다. 이 문제를 해결하는 더 쉬운 보편적 인 방법이 없습니까? 폴리 필은 어떻습니까?
Reado dec.

1
당신은 내 인생 <3 저장
크리스티안 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>

참고 사항 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
좋은 충고. 나는이 문제가 없지만 이것이 대답으로 전 세계적 일 수 있다고 생각합니다. 맥주를 마친 후에 추가하겠습니다
micaball 2017

3
@gentleboy REGEX를 사용하여 OS 11을 찾는 것은 어떻습니까? 그러면 각 OS 11 업데이트를 코드로 업데이트 할 필요가 없습니까? 이 같은iOS11 = /OS 11_(\d{1,2})(_{0,1})(\d{1,2})/.test(us);
T. 에반스

1
이에 따라 여전히 11.2 베타에 존재 11.3 @RonakK처럼 보인다는 bugs.webkit.org
micaball

2
@ T.Evans 그 정규식이 작동하지 않습니다. : 원래 올바른 정규식은 다음과 같이 수 있습니다ios11 = /OS 11_(\d{1,2})/.test(ua);
아브라함

2
고정 된 위치는 여전히 문서 / 본문 스크롤을 맨 위로 이동합니다. 모달이 열리면 현재 scrollTop 위치를 잡고 모달이 닫히면 scrollTop 값을 읽는 것이 좋습니다. 이것처럼 jsfiddle.net/im4aLL/hmvget9x/1
HADI

15

이 문제는 부트 스트랩과 사파리를 넘어 섭니다. 모든 브라우저에서 발생하는 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

실망스러운 버그입니다. 확인해 주셔서 감사합니다. 그렇지 않으면 아이폰이나 머리를 벽에 부딪 히게됩니다.

가장 간단한 수정은 다음과 같습니다 (코드 한 줄 변경).

다음 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


이것이 답이되어야합니다. 부트 스트랩은 모달이 표시 될 때 모달 개방 클래스를 본문에 추가합니다. 해당 클래스를 대상으로하기 만하면됩니다.
lfkwtz

1
나는이 문제를 얼마 동안 다루어왔다. 고정 위치를 추가하면 페이지가 맨 위로 스크롤되므로이 솔루션은 나에게 적합하지 않습니다. 따라서 사용자가 모달을 닫으면 다른 스크롤 위치에있게됩니다. 이것은 끔찍한 사용자 경험으로 이어집니다
Nearpoint

이 수정은 모바일에서 Chrome을 사용할 때 효과적이었습니다. .modal-open이 모달 HTML에 나타나지 않기 때문에 처음에는 혼란 스러웠지만 어쨌든 내 헤더에 CSS로 추가했고 작동했습니다.
David

4

가장 쉽고 깨끗한 솔루션 :

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

1
이것이 가장 쉬운 해결책이며 작동하지만 유일한 문제는 커서가 완전히 사라진다는 것입니다. 초기 상황만큼 나쁘지는 않지만 사용성 문제가 있습니다.
tmo256 2011

이상합니다. 커서가 사라지는 것을 경험 한 적이 없습니다
lfkwtz 2011

1
나는 또한 사라지는 커서를 경험했습니다. 왜 그런 일이 일어날 수 있는지에 대한 생각이 있습니까?
Alex Burgos

4
예, 첫 번째 초점 이벤트에 대해 커서가 사라지는 것도보고 있습니다. 후속 입력 포커스에는 커서가 나타납니다. 아주 이상한. 이것은 iOS의 Safari에서만 발생합니다.
Devin Walker

@DevinWalker 너희들은 사라지는 커서 문제를 해결 했습니까?
부여

3

이 문제는 Apple 장치를 iOS 11.3으로 업데이트 한 후 더 이상 재현 할 수 없습니다.


무슨 말이야, 애플이 고쳤어?
Starscream

1
@Starscream 네,이 소프트웨어 버전과 사과로 (아이폰 OS 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
이 스레드의 다른 솔루션과 마찬가지로 모달이 닫히면 다시 맨 위로 돌아옵니다. 예 : 사용자가 항목 그리드를 스크롤하고, 모달에서 세부 정보를 시작합니다.이 수정 사항을 사용하면 모달을 닫을 때 .. 항목 그리드의 맨 위에 다시
나타나며

2
내 아이폰 7 플러스에이 수정 프로그램은 완전히 사라 내 커서의 원인
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 propertyof body를 설정 fixed하면iOS cursor misplacement 해결됩니다.

그러나 이러한 이득은 페이지 상단으로 강제 스크롤되는 비용으로 발생합니다.

다행히,이 새로운 UX문제를 활용하여 많은 오버 헤드없이 부정 할 수 HTMLElement.stylewindow.scrollTo() .

기본 요점은 요소의 when scroll to top을 조작하여 에 대응하는 것 입니다. 이 작업 은bodystyle.topmountingYOffsetygap 변수가 .

거기에서 단순히 body's style.topto 를 재설정하고 when을 0사용하여 사용자의 뷰를 재구성 하는 문제입니다.window.scrollTo(0, ygap)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를 함수에 넣고 모달이 닫힐 때 호출 할 것이라고 생각합니다.
Neal Jones

아 예. 무슨 말인지 알겠습니다. 수정 된 솔루션은 위를 참조하십시오. 또한; 예, 의도는 functions언제 mountingdismounting. 감사.
Arman Charan

-1

누구나 IOS> 11.2에서 작동하고 추가 CSS가 필요하지 않은 바닐라 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-11.2.5의 Safari인지 확인
  2. focusin페이지의 모든 이벤트를 듣 습니다.
  3. 포커싱 요소가있는 경우 input나을 textarea하고 갖는 요소에 포함되는 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에서 fixed로 변경absolute

.modal {
position: absolute !important;
}

1
내 시나리오에서 작동하지 않았습니다. 고정을 절대로 변경하면 많은 영향을 미칠 수 있습니다
Steve D

@SteveD-작동하게하려면 모달을 <body>에 추가해야합니다. 그리고 <body>는-position : relative를 가져야합니다. 그리고 그것이 작동해야 할 때 :)
Dan

-3

#modal 위치에 추가 : 절대 위치와 관련된 향후 문제 수정 : 수정 됨


귀하의 답변은 정확히 중복됩니다. 중복 답변을 게시하지 마십시오.
MechMK1
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.