désactiver le zoom de la fenêtre Safari iOS 10+?

164

J'ai mis à jour mon iPhone 6 plus vers la version bêta d'iOS 10 et je viens de constater que dans Mobile Safari, vous pouvez zoomer sur toutes les pages Web en appuyant deux fois ou en pinçant IGNORER le user-scalable=nocode dans la balise meta. Je ne sais pas si c'est un bug ou une fonctionnalité. Si cela est considéré comme une fonctionnalité, comment désactiver le zoom de la fenêtre Safari iOS 10?


mis à jour sur la version iOS 11/12, les safaris iOS 11 et iOS 12 NE respectent toujours PAS la user-scalable=nobalise meta.

site github mobile sur Safari

Sam Su
la source
2
Une fonctionnalité d'accessibilité: à noter dans Safari sur iOS 10 twitter.com/thomasfuchs/status/742531231007559680/photo/1
ErikE
87
Non, ça ne l'est pas. C'est une mauvaise pratique pour le contenu Web normal. Pour les applications Web, le comportement de zoom par défaut peut ruiner complètement la convivialité. Par exemple, personne ne souhaite effectuer un zoom avant sur un bouton de chaîne haut parce qu'il l'a tapé deux fois, ni zoomer sur une partie d'un jeu vidéo parce qu'il a appuyé deux fois sur le bouton de saut. Il y a une raison pour laquelle cette fonctionnalité a été ajoutée en premier lieu, et cela n'a aucun sens d'interrompre la convivialité pour tout le monde simplement parce que quelques "concepteurs Web" ne savent pas ce qu'ils font. Allez crier aux concepteurs du site et arrêtez de casser le navigateur.
dgatwood
36
Dire que c'est une "mauvaise pratique" est une opinion et ne change pas le fait qu'Apple insiste pour adopter les standards du Web que la communauté passe des mois / années / décennies à mettre en œuvre multiplateforme et à s'en prendre à une merde géante. Pourquoi Apple devrait-il imposer aux concepteurs Web de ne pas savoir ce qu'ils font? Terrible argument.
samrap
2
Personnellement, je pense que cela provient du code standard en ligne où les développeurs se contentent de copier et coller aveuglément sans savoir quel est le but du code.
William Isted
7
La réponse est simple, Apple: faites de la désactivation de la balise meta un paramètre d'accessibilité désactivé par défaut. Ceux qui en ont besoin l'auront, sans punir ceux qui n'en ont pas.
Ruben Martinez Jr.

Réponses:

94

Il est possible d'empêcher la mise à l'échelle de la page Web dans Safari sur iOS 10, mais cela impliquera plus de travail de votre part. Je suppose que l'argument est qu'un certain degré de difficulté devrait empêcher les développeurs du culte de la cargaison de laisser tomber "user-scalable = no" dans chaque balise de la fenêtre et de rendre les choses inutilement difficiles pour les utilisateurs malvoyants.

Néanmoins, j'aimerais voir Apple modifier sa mise en œuvre afin qu'il existe un moyen simple (méta-balise) de désactiver le double-clic pour zoomer. La plupart des difficultés sont liées à cette interaction.

Vous pouvez arrêter le pincement 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, l'événement n'atteindra pas le document et le comportement de mise à l'échelle ne sera pas empêché par cet écouteur.

La désactivation du double-tap-to-zoom est similaire. Vous désactivez tout tap sur le document se produisant dans les 300 millisecondes du tap 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, vous concentrer sur une entrée effectuera un zoom automatique, et comme vous avez principalement désactivé le zoom manuel, il sera désormais presque impossible de dézoomer. Assurez-vous que la taille de la police d'entrée est> = 16px.

Si vous essayez de résoudre cela dans un WKWebView dans une application native, la solution donnée ci-dessus est viable, mais c'est une meilleure solution: https://stackoverflow.com/a/31943976/661418 . Et comme mentionné dans d'autres réponses, dans iOS 10 bêta 6, Apple a maintenant fourni un drapeau pour honorer la balise meta.

Mise à jour de mai 2017: j'ai remplacé l'ancienne méthode de désactivation du zoom par pincement par une approche plus simple de vérification de l'événement à l'échelle sur touchmove. Devrait être plus fiable pour tout le monde.

Joseph
la source
3
Notez que le hack de touchstart est incohérent ... et si vous parvenez à l'éviter, vous êtes coincé dans un état très inconfortable
Sam Saffron
5
Par exemple. applications de cartographie plein écran, il existe une fonction de zoom codée en dur dans l'application de cartographie (Google Maps JS, Leaflet, etc.). Google conseille d'ajouter une balise meta <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />et si le navigateur ne respecte pas la balise meta, c'est une très mauvaise conception du navigateur. L'autre conception très mauvaise est l'action arrière / avant par glissement, ce qui ne peut pas être empêché dans iOS 9/10. Il rompt gravement les actions de glissement dans l'application Web.
Timo Kähkönen
4
Si l'utilisateur commence à faire glisser avec un doigt, placez un deuxième doigt sur l'écran pour pouvoir pincer-zoomer. Vous pouvez désactiver les zooms et défilement avec preventDefaultle touchmove. Vous ne pouvez pas (complètement) désactiver le zoom sans désactiver le défilement.
Paolo
10
Wow, cette partie (je vais coller ici) m'a été SUPER utile. Je n'ai vu cela mentionné par personne d'autre PARTOUT sur Internet. Il m'a fallu des heures pour résoudre ce problème. Je suis vraiment déçu par les choix de conception UX d'Apple à ce sujet, où les formulaires effectuent un zoom avant automatique mais ne font pas de zoom arrière. If you don't set up your form elements right, focusing on an input will auto-zoom, and since you have mostly disabled manual zoom, it will now be almost impossible to unzoom. Make sure the input font size is >= 16px.
Ryan
6
Il semble que cela ne fonctionne plus sous iOS 12. Une idée comment faire fonctionner cela pour iOS 12?
TJR
78

Il s'agit d'une nouvelle fonctionnalité d'iOS 10.

À partir des notes de version d'iOS 10 bêta 1:

  • Pour améliorer l'accessibilité sur les sites Web dans Safari, les utilisateurs peuvent désormais pincer pour zoomer même lorsqu'un site Web est défini user-scalable=nodans la fenêtre d'affichage.

Je pense que nous allons bientôt voir un add-on JS pour désactiver cela d'une manière ou d'une autre.

Paul Gerarts
la source
4
@Onza: Je ne pense pas que ce soit mauvais. Je trouve ça bien. La désactivation du pincement / zoom (comportement de l'utilisateur par défaut) est considérée comme mauvaise, et de nombreux sites Web mobiles le font. Le seul cas utilisateur acceptable serait une véritable application Web qui ressemble et se sent comme une application.
wouterds
6
Mauvais .. Je change de fenêtre en utilisant js et bloque le zoom uniquement lorsque certains éléments sont sélectionnés sur le site Web maintenant, il est cassé à cause de cette "décision". Si quelqu'un décide de le bloquer, il y a une raison.
Zhenya le
9
@Karlth c'est très lit pour un développeur de jeux
Sandeep
14
J'ai IOS 10.0.2, évolutif par l'utilisateur = no ne désactive plus le zoom sur notre site Web ... Notre principal problème avec le zoom est avec notre menu latéral fixe .. Il ne fait que casser la mise en page .. Des idées ou des solutions à ce sujet? Je comprends que le zoom est bon pour l'accessibilité, nous avons rendu le zoom disponible sur des parties spécifiques de notre site en utilisant js events (hammer) & css .. Je ne vois pas pourquoi une règle doit être imposée à tout le monde, on dirait que la police PC commence prendre le contrôle de notre monde de développement aussi?!
webkit
50
"Le seul cas utilisateur acceptable serait une véritable application Web qui ressemble et se sent comme une application." - et c'est, comme vous l'avez dit, un cas d'utilisation réel et acceptable, ce n'est pas si rare ..
Florrie
21

J'ai pu résoudre ce problème en utilisant la touch-actionpropriété css sur des éléments individuels. Essayez de définir des touch-action: manipulation;éléments sur lesquels on clique généralement, comme des liens ou des boutons.

Iainbeeston
la source
1
La "manipulation" n'empêche pas le zoom par pincement, seulement un zoom double.
Moos
4
Cela devrait être la réponse acceptée. vous pouvez utiliser touch-action: none;pour contrôler tous les gestes vous-même.
Guy Sopher
4
c'est génial - désactiver le zoom double-tap tout en laissant le zoom par pincement, ce qui DEVRAIT être considéré comme un geste - le double tapotement ne devrait pas. 1 chien est un chien. 1 chien + 1 chien ne fait pas une navette spatiale. Cela fait 2 chiens et ils font des choses que vous attendez de 2 chiens. Je ne m'attendais jamais à ce que 2 chiens soient une navette spatiale. Jamais.
Larry
5
@GuySopher iOS ne fournit pastouch-action: none seulement manipulatoin, ce qui laisse le problème du pincement-zoom tel quel.
humanityANDpeace
14

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

À partir des notes de publication pour iOS 10 bêta 6:

WKWebViewdésormais, par défaut, respecter user-scalable=nodepuis une fenêtre. Les clients de WKWebViewpeuvent améliorer l'accessibilité et permettre aux utilisateurs de pincer pour zoomer sur toutes les pages en définissant la WKWebViewConfiguration propriété ignoresViewportScaleLimitssur YES.

Cependant, dans mes tests (très limités), je ne peux pas encore confirmer que ce soit le cas.

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

Cellane
la source
11
10.0.1 ici. Ne le respecte pas. Qu'est-ce que Apple se débarrasse des fonctionnalités dont tout le monde a besoin ...
lifwanian
1
Cela ne fait WKWebView pas référence à Safari. Source: Une de nos applications de carte est tombée en panne et nous ne savons pas comment la réparer.
Fabio Poloni
Ah! Toutes mes excuses, je suis venu ici lors de la recherche d'une solution pour le même bogue / fonctionnalité WKWebViewet j'ai en quelque sorte supposé que la question d'origine était posée WKWebViewlors de la rédaction de ma réponse. Donc, je suppose que lors de l'une des premières versions bêta, Apple a changé le comportement de WKWebViewSafari et du mobile Safari, puis en bêta 6, ils ont inversé le comportement de WKWebViewmais l'ont conservé pour le Safari mobile.
Cellane
1
10.0.2 ne respecte pas user-scalable=no. Je ne sais pas pourquoi ils annuleraient cela, uniquement pour le ramener, pour le supprimer à nouveau.
Aidan Hakimian
13

La solution de contournement qui fonctionne dans Mobile Safari au moment de la rédaction consiste à avoir le troisième argument dans addEventListenerbe { passive: false }, donc la solution de contournement complète ressemble à ceci:

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

Vous voudrez peut-être vérifier si les options sont prises en charge pour rester rétrocompatibles.

Casper Fabricius
la source
3
Quelqu'un a essayé cela sur iOS 12? J'ai ajouté le code ci-dessus et cela ne fait rien pour mon application Web. Toujours capable de zoomer dans ce stupide Safari. Mes meta tag viewport se présente comme suit: btw <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">.
Patrick DaVader
2
@PatrickDaVader Oui, je ne trouve aucune solution de travail pour iOS 12 Safari. Avoir le mal de mer à cause de tous les zooms incessants.
Jamie Birch
1
Celui-ci fonctionne sous iOS 13. Mes balises <meta> incluent: <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, viewport-fit=cover, user-scalable=no, shrink-to-fit=no" />et<meta name="HandheldFriendly" content="true">
Sterling Bourne
1
@SterlingBourne Copie votre configuration. Fonctionne, mais seulement 90% du temps. Je ne sais pas pourquoi pas tout le temps.
Hillcow
1
La réponse @SterlingBourne a fonctionné pour moi! Merci. Il devrait le publier comme une réponse plutôt que comme un commentaire afin qu'il puisse être voté <meta name = "viewport" content = "width = device-width, initial-scale = 1, maximum-scale = 1, viewport-fit = cover, user-scalable = no, shrink-to-fit = no "/> et <meta name =" HandheldFriendly "content =" true ">
Gene Black
8

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 joué avec hammer.js (Hammer.js est une bibliothèque qui vous permet de manipuler facilement toutes sortes d'événements tactiles) et que j'ai surtout échoué dans ce que j'essayais de faire.

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

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>

sporker
la source
J'ai également essayé de résoudre ce problème en travaillant avec hammer.js, et je peux confirmer que je pouvais empêcher le zoom de la fenêtre en ajoutant un .preventDefaultà tous les gestionnaires de mouvements de marteau. J'utilise swipe / pinch / pan / tap ensemble, je l'ai ajouté à tous les gestionnaires, je ne sais pas s'il y en a un en particulier qui fait le travail.
Conan
6

J'ai essayé la réponse précédente à propos du pincement pour zoomer

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

Cependant, parfois, l'écran continue de zoomer lorsque event.touches.length> 1 J'ai découvert que le meilleur moyen est d'utiliser l'événement touchmove, pour éviter que le doigt ne bouge sur l'écran. Le code sera quelque chose comme ceci:

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

J'espère que cela aidera.

Chihying Wu
la source
7
Cela ne fonctionne que si votre application est parfaitement adaptée ... si vous avez un contenu déroulant, cela ne fonctionne pas ... encore une bonne astuce pour certains scénarios.
eljamz le
8
Cela désactive même le défilement sur le site Web. BAD
Gags
@eljamz merci de m'avoir fait savoir et oui ... mon application est parfaitement adaptée à l'écran.
Chihying Wu
@Gags Je n'ai pas encore testé la fonction de défilement, merci de me le faire savoir.
Chihying Wu
6

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);
Parmod
la source
2
iOS 13 change false en {passive: false}
wayofthefuture
6

Nous pouvons obtenir tout ce que nous voulons en injectant une règle de style et en interceptant les é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-tap.

✔ Le défilement n'est pas affecté.

✔ Désactive la mise en évidence des touches (qui est déclenchée, sur iOS, par la règle de style).

AVIS: ajustez la détection iOS à votre guise. Plus à ce sujet ici .


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

jeff_mcmahan
la source
Cela fonctionne sur mon émulateur iPad qui exécute iOS 11.2. Sur mon vrai iPad sous iOS 11.3, cela ne fonctionne pas. J'ai ajouté un console.log pour m'assurer que les événements sont déclenchés et qu'ils apparaissent donc dans la console. C'est quelque chose à voir avec iOS 11.3? Ou avec de vrais appareils?
Mathieu R.
1
@MathieuR. C'est un problème iOS 11.3. Il peut être rectifié en utilisant l'une des addEventListenerréponses basées et en passant { passive: false }comme optionsparamètre au lieu de false. Cependant, pour la compatibilité descendante, vous devez réussir à falsemoins que le passivechamp d'option ne soit pris en charge. Voir developer.mozilla.org/en-US/docs/Web/API/EventTarget/...
Josh Gallagher
@JoshGallagher Pouvez-vous fournir un exemple concret? Sur iOS11, aucune des réponses ne fonctionne pour moi.
Mick
Le 'gesturestart' -> preventDefault fonctionne pour moi au moment de l'écriture sur iOS 12,2
Michael Camden
5

J'ai trouvé une solution assez naïve, mais elle semble fonctionner. Mon objectif était d'éviter que les doubles-taps accidentels soient interprétés comme un zoom avant, tout en gardant le pincement pour zoomer pour l'accessibilité.

L'idée est de mesurer le temps entre le premier touchstartet le second touchenden un double tap, puis d'interpréter le dernier touchendcomme un clic si le délai est trop petit. Tout en évitant un zoom accidentel, cette méthode semble ne pas affecter le défilement de la liste, ce qui est bien. Je ne sais pas si je n'ai rien manqué.

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 essentiel de l'hiver mutuel et la réponse de Joseph .

Alexandre Kachkaev
la source
5

Dans mon cas particulier, j'utilise Babylon.js pour créer une scène 3D et toute ma page se compose d'un canevas plein écran. Le moteur 3D a sa propre fonctionnalité de zoom, mais sur iOS, le zoom par pincement interfère avec cela. J'ai mis à jour la réponse @Joseph pour surmonter mon problème. Pour le désactiver, j'ai compris que je devais passer le {passif: false} comme option à l'écouteur d'événements. Le code suivant fonctionne pour moi:

window.addEventListener(
    "touchmove",
    function(event) {
        if (event.scale !== 1) {
            event.preventDefault();
        }
    },
    { passive: false }
);
Hamed
la source
Mon cas d'utilisation est également une scène 3D pleine page avec des commandes de pincement personnalisées. J'aurais été coulé s'il n'y avait pas de solution de contournement à Apple ignorant explicitement l'échelle de l'utilisateur: pas de méta.
Nick Bilyk
1

Aussi étrange que cela puisse paraître, au moins pour Safari dans iOS 10.2, le double tap pour zoomer est désactivé par magie si votre élément ou l'un de ses ancêtres présente l'un des éléments suivants:

  1. Un auditeur onClick - cela peut être un simple noop.
  2. Un cursor: pointerensemble en CSS
mariomc
la source
que diriez-vous de pincer?
Sam Su
Malheureusement, le pincement pour zoomer n'est pas couvert par cette solution. Pour cela, nous avons utilisé la solution proposée dans: stackoverflow.com/a/39594334/374196
mariomc
Ça ne marche pas pour moi. J'utilise 10.2.1 Beta 4 sur un iPod Touch en utilisant cette page de test et en appuyant deux fois sur l'un des zooms carrés gris: jsbin.com/kamuta/quiet
robocat
1
J'ai ceci sur une durée dans une application de réaction et cela ne fonctionne pas.
fièvre aphteuse
1

Un zoom non intentionnel a tendance à se produire lorsque:

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

Pour éviter le comportement de 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>

Ces deux éléments empêchent Safari (iOS 10.3.2) de zoomer sur le bouton. Comme vous pouvez le voir, l'un est uniquement 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) tenté d'empêcher le comportement de pincement, principalement parce que j'ai tendance à ne pas créer d'interfaces multi-touch pour le Web et deuxièmement, je suis venu à l'idée que toutes les interfaces, y compris l'interface utilisateur native de l'application, devraient être "pincées pour zoomer" -able par endroits. Je continuerais de concevoir pour éviter que l'utilisateur n'ait à le faire pour lui rendre votre interface utilisateur accessible à tout prix.

Lukejacksonn
la source
1

Trouvé ce travail simple autour qui semble empêcher le double-clic pour 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);
Syntaxe
la source
1

Comme demandé, j'ai transféré mon commentaire dans une réponse afin que les gens puissent le voter:

Cela fonctionne 90% du temps pour iOS 13:

<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, viewport-fit=cover, user-scalable=no, shrink-to-fit=no" />

et

<meta name="HandheldFriendly" content="true">

Sterling Bourne
la source
0

J'ai vérifié toutes les réponses ci-dessus dans la pratique avec ma page sur iOS (iPhone 6, iOS 10.0.2), mais sans succès. Voici 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)'
    }
});
Piotr Kowalski
la source
Malheureusement, cela ne fonctionne que lorsque votre page est parfaitement ajustée, pas lorsque vous avez un contenu à défilement
Chaussure
Hmm. Cela fonctionne bien avec le contenu déroulant, d'après mon expérience (iOS 10.3).
jeff_mcmahan
0

cela a fonctionné pour moi:

document.documentElement.addEventListener('touchmove', function (event) {
    event.preventDefault();
}, false);
Diego Santa Cruz Mendezú
la source
J'ai essayé cela, cela a empêché le zoom par pincement, mais il désactive le défilement tactile de la fenêtre afin que vous ne puissiez plus faire défiler la page de haut en bas.
TGR le