web-dev-qa-db-fra.com

désactiver la fenêtre d'affichage zoomer iOS 10+ safari?

J'ai mis à jour mon iPhone 6 plus vers la version bêta d'iOS 10 et je viens de constater que, dans un safari mobile, vous pouvez zoomer sur n'importe quelle page Web en appuyant deux fois sur ou en pinçant IGNORE le code user-scalable=no dans la balise méta. Je ne sais pas si c'est un bug ou une fonctionnalité. Si c'est considéré comme une fonctionnalité, comment désactiver le zoom de la fenêtre d'affichage iOS 10 Safari?


mis à jour sur la version iOS 11/12, les safaris iOS 11 et iOS 12 respectent toujours PAS respectent la balise méta user-scalable=no.

 mobile github site on Safari

131
Sam Su

Il est possible d'empêcher la mise à l'échelle des pages Web dans Safari sur iOS 10, mais cela nécessitera davantage de travail de votre part. Je suppose que l’argument est qu’un certain degré de difficulté devrait empêcher les développeurs voués au fret d’envoyer de "user-scalable = no" dans chaque tag de viewport et de rendre les choses inutilement difficiles pour les utilisateurs malvoyants.

Néanmoins, j'aimerais que Apple modifie leur implémentation afin qu'il existe un moyen simple (méta-tag) de désactiver le double-clic sur le zoom. La plupart des difficultés sont liées à cette interaction.

Vous pouvez arrêter de pincer pour zoomer avec quelque chose comme ceci:

document.addEventListener('touchmove', function (event) {
  if (event.scale !== 1) { event.preventDefault(); }
}, false);

Notez que si des cibles plus profondes appellent stopPropagation sur l'événement, celui-ci n'atteindra pas le document et le comportement de la mise à l'échelle ne sera pas empêché par cet écouteur.

La désactivation du double-clic sur le zoom est similaire. Vous désactivez tout appui sur le document qui se produit dans les 300 millisecondes de l'appui précédent:

var lastTouchEnd = 0;
document.addEventListener('touchend', function (event) {
  var now = (new Date()).getTime();
  if (now - lastTouchEnd <= 300) {
    event.preventDefault();
  }
  lastTouchEnd = now;
}, false);

Si vous ne configurez pas correctement vos éléments de formulaire, le zoom sur la saisie est auto-zoomé et, comme vous avez pour la plupart désactivé le zoom manuel, il sera désormais presque impossible de le dézoomer. Assurez-vous que la taille de la police d'entrée est> = 16px.

Si vous essayez de résoudre ce problème dans un WKWebView dans une application native, la solution ci-dessus est viable, mais il s'agit d'une meilleure solution: https://stackoverflow.com/a/31943976/661418 . Et comme mentionné dans d'autres réponses, dans iOS 10 beta 6, Apple a maintenant fourni un drapeau pour honorer la balise méta.

Mise à jour mai 2017: J'ai remplacé l'ancienne méthode de désactivation du zoom par pincement 'check touch length on touchstart' par une approche plus simple, 'check event.scale on touchmove'. Devrait être plus fiable pour tout le monde.

79
Joseph

Ceci est une nouvelle fonctionnalité dans iOS 10.

À partir des notes de publication iOS 10 beta 1:

  • Pour améliorer l'accessibilité sur les sites Web dans Safari, les utilisateurs peuvent désormais effectuer un zoom avant même lorsqu'un site Web définit user-scalable=no dans la fenêtre d'affichage.

Je pense que nous allons bientôt voir un add-on JS pour le désactiver.

75
Paul Gerarts

Il semble que ce comportement soit censé avoir été modifié dans la dernière version bêta, qui était au moment de la rédaction de la version 6.

D'après les notes de publication pour iOS 10 Bêta 6:

WKWebView permet maintenant par défaut de respecter user-scalable=no dans une fenêtre . Les clients de WKWebView peuvent améliorer l’accessibilité et permettre aux utilisateurs de pincer pour zoomer sur toutes les pages en définissant la WKWebViewConfiguration property ignoresViewportScaleLimits to YES.

Cependant, lors de mes tests (très limités), je ne peux pas encore confirmer que tel est le cas.

Edit: vérifié, iOS 10 Beta 6 respecte user-scalable=no par défaut pour moi.

14
Cellane

J'ai pu résoudre ce problème en utilisant la propriété touch-action css sur des éléments individuels. Essayez de définir touch-action: manipulation; sur des éléments sur lesquels vous cliquez souvent, tels que des liens ou des boutons.

13
iainbeeston

J'ai passé environ une heure à chercher une option javascript plus robuste et je n'en ai pas trouvé. Il se trouve que ces derniers jours, j'ai manipulé hammer.js (Hammer.js est une bibliothèque qui vous permet de manipuler facilement toutes sortes d’événements tactiles) et surtout d’échouer à ce que j’essayais de faire. faire.

Avec cette mise en garde, et bien comprendre que je ne suis en aucun cas un expert en javascript, c'est une solution que j'ai proposée qui utilise essentiellement hammer.js pour capturer les événements zoom-pincé et double-tap puis les enregistrer et les ignorer.

Assurez-vous d'inclure hammer.js dans votre page, puis essayez de coller ce javascript quelque part dans la tête:

< script type = "text/javascript" src="http://hammerjs.github.io/dist/hammer.min.js"> < /script >
< script type = "text/javascript" >

  // SPORK - block pinch-zoom to force use of tooltip zoom
  $(document).ready(function() {

    // the element you want to attach to, probably a wrapper for the page
    var myElement = document.getElementById('yourwrapperelement');
    // create a new hammer object, setting "touchAction" ensures the user can still scroll/pan
    var hammertime = new Hammer(myElement, {
      prevent_default: false,
      touchAction: "pan"
    });

    // pinch is not enabled by default in hammer
    hammertime.get('pinch').set({
      enable: true
    });

    // name the events you want to capture, then call some function if you want and most importantly, add the preventDefault to block the normal pinch action
    hammertime.on('pinch pinchend pinchstart doubletap', function(e) {
      console.log('captured event:', e.type);
      e.preventDefault();
    })
  });
</script>

6
sporker

J'ai essayé la réponse précédente sur pincer pour zoomer

document.documentElement.addEventListener('touchstart', function (event) {
    if (event.touches.length > 1) {
        event.preventDefault();
    }
}, false);

cependant, il arrive parfois que l'écran continue à zoomer lorsque event.touches.length> 1 J'ai découvert que le meilleur moyen consiste à utiliser l'événement touchmove pour éviter tout mouvement du doigt sur l'écran. Le code ressemblera à ceci:

document.documentElement.addEventListener('touchmove', function (event) {
    event.preventDefault();      
}, false);

J'espère que ça va aider. 

5
Chihying Wu

Vérifiez le facteur d'échelle dans l'événement touchove, puis évitez l'événement tactile.

document.addEventListener('touchmove', function(event) {
    event = event.originalEvent || event;
    if(event.scale > 1) {
        event.preventDefault();
    }
}, false);
5
Parmod

Je suis arrivé avec une solution assez naïve, mais elle semble fonctionner… .. Mon objectif était d'empêcher que les doubles-tapages accidentels soient interprétés comme un zoom avant, tout en conservant le pincement pour zoomer afin d'améliorer l'accessibilité.

L'idée est de mesurer le temps entre la première touchstart et la deuxième touchend lors d'un double tap, puis d'interpréter la dernière touchend comme un clic si le retard est trop petit. Tout en empêchant le zoom accidentel, cette méthode semble garder le défilement de la liste inchangé, ce qui est agréable. Pas sûr si je n'ai rien manqué cependant.

let preLastTouchStartAt = 0;
let lastTouchStartAt = 0;
const delay = 500;

document.addEventListener('touchstart', () => {
  preLastTouchStartAt = lastTouchStartAt;
  lastTouchStartAt = +new Date();
});
document.addEventListener('touchend', (event) => {
  const touchEndAt = +new Date();
  if (touchEndAt - preLastTouchStartAt < delay) {
    event.preventDefault();
    event.target.click();
  }
});

Inspiré par un Gist de mutewinter et réponse de Joseph .

4

Nous pouvons obtenir tout ce que nous voulons en injectant une règle de style et en interceptant des événements de zoom:

$(function () {
  if (!(/iPad|iPhone|iPod/.test(navigator.userAgent))) return
  $(document.head).append(
    '<style>*{cursor:pointer;-webkit-tap-highlight-color:rgba(0,0,0,0)}</style>'
  )
  $(window).on('gesturestart touchmove', function (evt) {
    if (evt.originalEvent.scale !== 1) {
      evt.originalEvent.preventDefault()
      document.body.style.transform = 'scale(1)'
    }
  })
})

✔ désactive le zoom par pincement.

✔ Désactive le zoom à double frappe.

✔ Scroll n'est pas affecté.

✔ Désactive la mise en surbrillance du toucher (déclenchée sous iOS par la règle de style).

AVIS: Ajustez la détection iOS à votre convenance. Plus sur cela ici .


Mes excuses à lukejackson et Piotr Kowalski, dont les réponses apparaissent sous une forme modifiée dans le code ci-dessus.

4
jeff_mcmahan

La solution de contournement qui fonctionne dans Mobile Safari en ce moment, est d'avoir le troisième argument dans adddEventListener être { passive: false }, afin que la solution de contournement complète ressemble à ceci:

document.addEventListener('touchmove', function (event) {
  if (event.scale !== 1) { event.preventDefault(); }
}, { passive: false });

Vous souhaiterez peut-être vérifier si les options sont supportées pour rester compatible avec les versions antérieures.

2
Casper Fabricius

Dans mon cas particulier, j'utilise Babylon.js pour créer une scène 3D et ma page entière est composée d'une toile plein écran. Le moteur 3D possède sa propre fonctionnalité de zoom, mais sous iOS, le pincement au zoom interfère avec cela. J'ai mis à jour la réponse @Joseph pour résoudre mon problème. Pour le désactiver, j'ai compris que je devais transmettre l'option {passive: false} à l'écouteur d'événements. Le code suivant fonctionne pour moi:

window.addEventListener(
    "touchmove",
    function(event) {
        if (event.scale !== 1) {
            event.preventDefault();
        }
    },
    { passive: false }
);
2
Hamed

Un zooming involontaire a tendance à se produire lorsque:

  • Un utilisateur appuie deux fois sur un composant de l'interface
  • Un utilisateur interagit avec la fenêtre d'affichage à l'aide de deux chiffres ou plus (pincement)

Pour éviter le comportement double tap, j'ai trouvé deux solutions de contournement très simples:

<button onclick='event.preventDefault()'>Prevent Default</button>
<button style='touch-action: manipulation'>Touch Action Manipulation</button>

Les deux empêchent Safari (iOS 10.3.2) de zoomer sur le bouton. Comme vous pouvez le voir, l’un n’est que JavaScript, l’autre est uniquement CSS. Utilisez de manière appropriée.

Voici une démo: https://codepen.io/lukejacksonn/pen/QMELXQ

Je n'ai pas encore essayé d'empêcher le comportement de pincement, principalement parce que je n'ai pas tendance à créer d'interfaces tactiles multiples pour le Web. Deuxièmement, je suis venu à l'idée que toutes les interfaces, y compris l'interface utilisateur d'application native, devraient être "pincer pour zoomer". -able par endroits. J'aurais quand même l'intention d'éviter que l'utilisateur [à] fasse cela pour que votre interface utilisateur leur soit accessible à tout prix.

1
lukejacksonn

Trouvé ce travail simple qui semble empêcher le double-clic de zoomer:

    // Convert touchend events to click events to work around an IOS 10 feature which prevents
    // developers from using disabling double click touch zoom (which we don't want).
    document.addEventListener('touchend', function (event) {
        event.preventDefault();
        $(event.target).trigger('click');
    }, false);
1
Syntax

Aussi étrange que cela puisse paraître, au moins pour Safari dans iOS 10.2, appuyer deux fois pour zoomer est désactivé comme par magie si votre élément ou l'un de ses ancêtres présente l'une des caractéristiques suivantes:

  1. Un auditeur onClick - ça peut être un simple noop.
  2. Un cursor: pointer défini en CSS
1
mariomc

cela a fonctionné pour moi:

document.documentElement.addEventListener('touchmove', function (event) {
    event.preventDefault();
}, false);

J'ai vérifié toutes les réponses ci-dessus en pratique avec ma page sur iOS (iPhone 6, iOS 10.0.2), mais sans succès. Ceci est ma solution de travail:

$(window).bind('gesturestart touchmove', function(event) {
    event = event.originalEvent || event;
    if (event.scale !== 1) {
         event.preventDefault();
         document.body.style.transform = 'scale(1)'
    }
});
0
Piotr Kowalski

Si rien de ce qui précède ne vous convient, il vous suffit de définir la taille de la police dans la zone sur 16 pixels pour résoudre le problème.

0
Jamie Burton