Modaler Textbereich für iOS 11 Safari Bootstrap außerhalb des Cursors


85

Bei der Safari mit iOS 11 befindet sich der Eingabe-Textfeld-Cursor außerhalb des Eingabe-Textfelds. Wir haben nicht verstanden, warum es dieses Problem gibt. Wie Sie sehen können, ist mein fokussiertes Textfeld eine E-Mail-Texteingabe, aber mein Cursor befindet sich außerhalb davon. Dies geschieht nur mit iOS 11 Safari

Problem


1
Dies ist ein Fehler bei Safari. Apple hat es intern behoben, aber das Update ist noch nicht in einer öffentlichen (oder sogar Beta-) Version von iOS enthalten. bugs.webkit.org/show_bug.cgi?id=176896
Käfer

Antworten:


69

Ich habe das Problem behoben, indem ich position:fixedden Körper beim Öffnen eines Modals erweitert habe. Hoffe das wird dir helfen.


6
Hinweis zu den Antworten unten - Bootstrap fügt .modal-open zum Körper hinzu, wenn das Modal geöffnet ist, sodass Sie einfach die Position hinzufügen können: fest für diese Klasse.
Timmyc

1
Möglicherweise müssen Sie auch hinzufügen width:100%, um die Körperbreite auf die Gerätebreite zu beschränken. In einigen Fällen kann dies je nach vorhandenem Markup ein Problem sein. Ich mag auch die Lösung von @gentleboy (unten), um andere Browser nicht ohne Probleme zu bestrafen, denn wenn der Körper auf fest eingestellt wird, rollt der Körper nach oben, was etwas ärgerlich ist.
Redtopia

Seltsamerweise hatte ich dieses Problem mit einer Anwendung, die mit Meteor-Cordova erstellt wurde. Es schien, als hätte jedes iOS-Gerät mit Version 11 + dieses Problem. In meinem Fall hatte ich mich bereits position:fixedbeim Hauptteil des Antrags beworben. Stattdessen habe ich es in position:absolutedas htmlElement geändert und mein Problem behoben. Danke Jen!
Adam Ross Bowers

1
Dies könnte für uns das Ende modaler Formen sein. Selbst wenn Apple das Problem behebt, muss der Benutzer sein Gerät aktualisieren, um das Arbeitsformular anzuzeigen. Gibt es nicht einen einfacheren universellen Weg, dies zu beheben? Was ist mit einer Polyfüllung?
Reado

1
Du hast mein Leben gerettet <3
Cristian B.

42

Scrollen Sie persönlich position: fixed automatisch nach oben . Ziemlich nervig !

Um andere Geräte und Versionen nicht zu bestrafen, wende ich diesen Fix nur auf die entsprechenden Versionen von iOS an.


** VERSION 1 - Alle Modalitäten behoben **

Für das 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");

    }

});

Für das CSS

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

** VERSION 2 - Nur ausgewählte Modalitäten **

Ich habe die Funktion so geändert, dass sie nur für ausgewählte Modalitäten mit einer Klasse ausgelöst wird .inputModal

Nur die Modalitäten mit Eingängen sollten beeinflusst werden, um ein Scrollen nach oben zu vermeiden.

Für das 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);
                }
            });

        }
    })();
});

Für das CSS

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

Für den HTML- Code Fügen Sie die Klasse inputModal zum Modal hinzu

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

Nota bene Die Javascript-Funktion ruft jetzt selbst auf


** UPDATE iOS 11.3 - Fehler behoben 😃🎉 **

Ab iOS 11.3 wurde der Fehler behoben. Es besteht keine Notwendigkeit, auf OS 11_in zu testeniOS11 = /OS 11_0|OS 11_1|OS 11_2/.test(ua);

Seien Sie jedoch vorsichtig, da iOS 11.2 immer noch weit verbreitet ist (Stand April 2018). Sehen

stat 1

stat 2


2
Netter Rat. Ich habe dieses Problem nicht, aber ich denke, dies könnte als Antwort global sein. Ich werde es hinzufügen, nachdem ich mein Bier beendet habe
Micaball

3
@gentleboy Warum nicht ein REGEX verwenden, um ein OS 11 zu finden? Auf diese Weise müssten Sie nicht jedes OS 11-Update auf Ihren Code aktualisieren? so etwasiOS11 = /OS 11_(\d{1,2})(_{0,1})(\d{1,2})/.test(us);
T. Evans

1
@ RonakK es sieht so aus, als ob es laut bugs.webkit.org
micaball

2
@ T. Evans, dass Regex nicht funktioniert. Eine korrekte Regex könnte ungefähr so ​​aussehen:ios11 = /OS 11_(\d{1,2})/.test(ua);
Abraham

2
Bei fester Position wird das Dokument / der Körper weiterhin nach oben gescrollt. Ich schlage vor, die aktuelle scrollTop-Position beim Öffnen des Modals zu erfassen und den scrollTop-Wert zu lesen, sobald das Modal geschlossen ist. So jsfiddle.net/im4aLL/hmvget9x/1
HADI

15

Dieses Problem geht über Bootstrap und nur über Safari hinaus. Es ist ein vollständiger Anzeigefehler in iOS 11, der in allen Browsern auftritt. Das obige Update behebt dieses Problem nicht in allen Fällen.

Der Fehler wird hier ausführlich gemeldet:

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

Angeblich haben sie es Apple bereits als Fehler gemeldet.


Dies scheint das Problem für mich zu sein, hat vor dem Update auf IOS 11 einwandfrei funktioniert. Android-Benutzer haben das Problem nicht.
Hackingchemist

11

Frustrierender Fehler, danke, dass Sie ihn identifiziert haben. Andernfalls würde ich mein iPhone oder meinen Kopf gegen die Wand schlagen.

Die einfachste Lösung ist (1 Zeile Codeänderung):

Fügen Sie einfach das folgende CSS zum HTML-Code oder zu einer externen CSS-Datei hinzu.

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

Hier ist ein voll funktionsfähiges Beispiel:

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

Ich habe hier ein Problem eingereicht: https://github.com/twbs/bootstrap/issues/24059


Dies sollte die Antwort sein. Bootstrap fügt die modal-open-Klasse dem Body hinzu, wenn ein Modal sichtbar ist. Sie müssen nur auf diese Klasse abzielen.
lfkwtz

1
Ich beschäftige mich seit einiger Zeit mit diesem Thema. Diese Lösung ist für mich unzureichend, da durch Hinzufügen einer festen Position die Seite wieder nach oben gescrollt wird. Wenn der Benutzer das Modal schließt, befindet er sich an einer anderen Bildlaufposition. Dies führt zu einer schrecklichen Benutzererfahrung
Nearpoint

Dieser Fix hat bei der Verwendung von Chrome auf Mobilgeräten funktioniert. War zunächst verwirrt, da .modal-open nicht im modalen HTML angezeigt wird, aber ich habe es trotzdem als CSS in meinen Header eingefügt und es hat funktioniert.
David

4

Einfachste / sauberste Lösung:

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

1
Dies ist die einfachste Lösung und funktioniert, aber das einzige Problem ist, dass der Cursor vollständig verschwindet. Es ist nicht so schlimm wie die Ausgangssituation, aber es gibt ein Usability-Problem.
tmo256


1
Ich habe auch den verschwindenden Cursor erlebt, irgendwelche Gedanken darüber, warum das passieren könnte?
Alex Burgos

4
Ja, ich sehe auch einen verschwindenden Cursor nur für das erste Fokusereignis. Bei nachfolgenden Eingabefokussen wird der Cursor angezeigt. Sehr eigenartig. Dies geschieht nur in Safari unter iOS.
Devin Walker

@DevinWalker habt ihr jemals das Problem mit dem verschwindenden Cursor gelöst?
Grant

3

Dieses Problem ist nach dem Update Ihrer Apple-Geräte auf iOS 11.3 nicht mehr reproduzierbar


Was meinst du damit, Apple hat es behoben?
Starscream

1
@ Starscream Ja, es wurde von Apple mit dieser Software-Version (iOS 11.3)
behoben

2

Hinzufügen position: fixed;, bodywenn Modal geöffnet ist.

$(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
Ähnlich wie bei anderen Lösungen in diesem Thread sind Sie nach dem Schließen des Modals wieder ganz oben. Beispiel: Der Benutzer scrollt durch das Raster der Elemente, startet Details in einem Modal. Mit diesem Fix befinden sie sich beim Schließen des
Modals

2
auf meinem iPhone 7 plus bewirkt dieses
Update

1

Diese Lösungen, die eine position: fixedPositionskorrektur basierend auf der scrollTopArbeit verwenden, funktionieren sehr gut, aber einige Leute (einschließlich ich) haben ein anderes Problem: Tastatur-Caret / Cursor werden nicht angezeigt, wenn die Eingaben fokussiert sind.

Ich beobachtete , dass caret / Cursor funktioniert nur , wenn wir NICHT DO verwenden position: fixedauf Körper. So , nachdem einige Dinge versuchen, gab ich auf mit diesem Ansatz und zur Verwendung entschieden position: relativeauf bodyund die Nutzung , scrollTopum eine korrekte modalen Spitzenposition statt.

Siehe Code unten:

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

Wie bereits erwähnt: die Einstellung style.position propertyvon bodybis fixedlöst das iOS cursor misplacementProblem.

Dieser Gewinn geht jedoch zu Lasten eines gewaltsamen Bildlaufs zum oberen Rand der Seite.

Glücklicherweise kann dieses neue UXProblem ohne großen Aufwand durch die Nutzung von HTMLElement.styleund behoben werden window.scrollTo().

Das Wesentliche ist, dem entgegenzuwirken, scroll to topindem man das Wann des bodyElements manipuliert . Dies erfolgt anhand des von der Variablen erfassten Werts .style.topmountingYOffsetygap

Von dort ist es nur darum , die zum Zurücksetzen body's style.topauf 0und Reframing der Sicht des Benutzers verwenden , window.scrollTo(0, ygap)wenn dismounting.

Unten finden Sie ein praktisches Beispiel.

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

}

Haben Sie ein detaillierteres Beispiel dafür? Ich vermute, ich hätte den Mount in einer Funktion, die aufgerufen wird, wenn das Modal geöffnet wird, und dann den Dismount in eine Funktion eingefügt und das aufgerufen, wenn das Modal geschlossen ist.
Neal Jones

Aahh yep. Ich verstehe was du meinst. Eine überarbeitete Lösung finden Sie oben. Ebenfalls; Ja, Sie möchten diese anrufen, functionswenn mountingund dismounting. Vielen Dank.
Arman Charan

-1

Falls jemand nach einem Fix in Vanilla JS sucht, der unter IOS> 11.2 funktioniert und kein zusätzliches CSS erfordert:

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

Was dies tut ist:

  1. Überprüfen Sie, ob der Browser Safari unter iOS 11.0.0 - 11.2.5 ist
  2. Achten Sie auf focusinEreignisse auf der Seite
  3. Wenn das fokussierte Element ein inputoder ein Element ist textareaund in einem Element mit fixedPosition enthalten ist, ändern Sie die Position des Containers in absoluteBezug auf scrollTopdie ursprünglichen Abmessungen des Containers.
  4. Stellen Sie bei Unschärfe die Position des Containers wieder her fixed.

-1

Diese Lösung hat bei mir funktioniert und funktioniert in allen Browsern unter 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

Überschreiben Sie modales CSS und ändern Sie es positionvon fixednachabsolute

.modal {
position: absolute !important;
}

1
Hat in meinem Szenario nicht funktioniert. Das Ändern von fest auf absolut kann VIELE Auswirkungen haben
Steve D

@SteveD - damit es funktioniert, sollten Sie Ihr Modal an <body> anhängen. Und der <Körper> sollte haben - Position: relativ. Und wenn es funktionieren sollte :)
Dan

-3

zur # modal Position hinzufügen: absolut behebt zukünftige Probleme im Zusammenhang mit der Position: behoben


Ihre Antwort ist ein genaues Duplikat. Bitte stellen Sie sicher, dass Sie keine doppelten Antworten veröffentlichen.
MechMK1
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.