web-dev-qa-db-fra.com

zone de texte modale pour iOS 11 Safari bootstrap en dehors du curseur

Avec iOS 11 safari, le curseur de la zone de saisie est en dehors de la zone de saisie. Nous n'avons pas compris pourquoi il avait ce problème. Comme vous pouvez le voir, ma zone de texte ciblée est la saisie de texte par courrier électronique, mais mon curseur est en dehors de celui-ci. Cela ne se produit qu'avec iOS 11 Safari 

 Problem

80
kekkeme

J'ai résolu le problème en ajoutant position:fixed au corps lors de l'ouverture d'un modal . J'espère que cela vous aidera.

66

Personnellement, position: fixedfaites défiler vers le haut automatiquement. Assez ennuyeux!

Pour éviter de pénaliser les autres périphériques et versions, j'applique ce correctif uniquement aux versions appropriées d'iOS.


** VERSION 1 - Correction de tous les modaux **

Pour le 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");

    }

});

Pour le CSS

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

** VERSION 2 - Modaux sélectionnés uniquement **

J'ai modifié la fonction pour qu'elle ne se déclenche que pour les modaux sélectionnés avec une classe .inputModal 

Seuls les modaux avec des entrées doivent être affectés pour éviter le défilement vers le haut.

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

        }
    })();
});

Pour le CSS

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

Pour le HTML Ajoutez la classe inputModal au modal

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

Nota bene La fonction javascript est maintenant auto-invoquante


** UPDATE iOS 11.3 - Bug corrigé ???????? **

Depuis iOS 11.3, le bogue a été corrigé. Il n'est pas nécessaire de tester OS 11_ dans iOS11 = /OS 11_0|OS 11_1|OS 11_2/.test(ua);

Mais soyez prudent car iOS 11.2 est encore largement utilisé (à partir d'avril 2018). Voir

stat 1

stat 2

42
micaball

Ce problème dépasse le cadre de Bootstrap et ne concerne pas que Safari. C'est un bug d'affichage complet dans iOS 11 qui se produit dans tous les navigateurs. Le correctif ci-dessus ne résout pas ce problème dans tous les cas.

Le bug est rapporté en détail ici:

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

Soi-disant, ils l'ont déjà signalé à Apple comme un bug.

15
Eric Shawn

Bogue frustrant, merci de l'identifier. Sinon, je cognerais mon iphone ou ma tête contre le mur. 

Le correctif le plus simple est (1 ligne de changement de code):

Il suffit d’ajouter le code CSS suivant au code HTML ou à un fichier css externe.

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

Voici un exemple de travail complet:

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

J'ai soumis un problème ici: https://github.com/twbs/bootstrap/issues/24059

11
Scott David Murphy

La solution la plus facile/la plus propre:

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

Ce problème ne peut plus être reproduit après la mise à jour de vos appareils Apple vers iOS 11.3

3

Ajoutez position: fixed; à body quand modal est ouvert.

$(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>

2
Anuruk S.

Ces solutions utilisant position: fixed et la correction de position basée sur scrollTop fonctionnent très bien, mais certaines personnes (dont moi) ont un autre problème: le curseur/curseur du clavier ne s'affiche pas lorsque les entrées sont focalisées.

J'ai observé que le curseur/curseur ne fonctionne que lorsque NE PAS utiliser position: fixed sur le corps. Donc, après avoir essayé plusieurs choses, j'ai renoncé à utiliser cette approche et décidé d'utiliser position: relative sur body et d'utiliser scrollTop pour corriger la première position de modal.

Voir le code ci-dessous:

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

Comme mentionné précédemment: définir le style.positionproperty de body sur fixed résout le problème iOS cursor misplacement

Cependant, ce gain se fait au prix d’un défilement forcé vers le haut de la page.

Heureusement, ce nouveau problème UX peut être annulé sans trop de charge en utilisant HTMLElement.style et window.scrollTo() .

Le Gist de base consiste à contrecarrer le scroll to top en manipulant le style.top lorsque body de l'élément mounting. Ceci est fait en utilisant la valeur YOffset capturée par la variable ygap.

À partir de là, il suffit simplement de réinitialiser le body'sstyle.top en 0 et de recadrer la vue de l'utilisateur à l'aide de window.scrollTo(0, ygap) quand dismounting.

Voir ci-dessous pour un exemple pratique.

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

}
0
Arman Charan