¿Deshabilitar el zoom de la ventana gráfica Safari iOS 10+?

164

Actualicé mi iPhone 6 plus a la versión beta de iOS 10 y acabo de descubrir que en el safari móvil, puede hacer zoom en cualquier página web tocando dos veces o pellizcando IGNORE el user-scalable=nocódigo en la metaetiqueta. No sé si es un error o una característica. Si se considera como una característica, ¿cómo deshabilitamos el zoom de viewport Safari para iOS 10?


actualizado en iOS 11/12, iOS 11 y iOS 12 safari todavía NO respetan la user-scalable=nometaetiqueta.

sitio móvil de github en Safari

Sam Su
fuente
2
Una característica de accesibilidad: Nota en Safari en iOS 10 twitter.com/thomasfuchs/status/742531231007559680/photo/1
ErikE
87
No lo es. Es una mala práctica para el contenido web normal. Para las aplicaciones web, el comportamiento de zoom predeterminado puede arruinar completamente la usabilidad. Por ejemplo, nadie quiere acercar un botón para subir el canal porque lo tocaron dos veces, ni acercar una parte de un videojuego porque tocaron el botón de salto dos veces. Hay una razón por la que esta característica se agregó en primer lugar, y no tiene sentido romper la usabilidad para todos solo porque algunos "diseñadores web" no saben lo que están haciendo. Ve a gritar a los diseñadores del sitio y deja de romper el navegador.
dgatwood
36
Decir que es una "mala práctica" es una opinión y no cambia el hecho de que Apple insiste en tomar estándares web que la comunidad pasa meses / años / décadas implementando multiplataforma y tomando una mierda gigante sobre ellos. ¿Por qué Apple debería dictar que los diseñadores web no saben lo que están haciendo? Terrible argumento.
samrap
2
Personalmente, creo que esto se deriva del código repetitivo en línea donde los desarrolladores simplemente copian y pegan a ciegas sin saber cuál es el propósito del código.
William Isted
77
La respuesta es simple, Apple: haga que deshabilitar la metaetiqueta sea una configuración de accesibilidad predeterminada. Quienes lo necesiten, lo tendrán, sin castigar a quienes no lo necesiten.
Ruben Martinez Jr.

Respuestas:

94

Es posible evitar el escalado de la página web en Safari en iOS 10, pero implicará más trabajo de su parte. Supongo que el argumento es que un cierto grado de dificultad debería evitar que los desarrolladores de culto de carga dejen "escalable por el usuario = no" en cada etiqueta de ventana gráfica y dificulten innecesariamente las cosas para los usuarios con discapacidad visual.

Aún así, me gustaría ver a Apple cambiar su implementación para que haya una forma simple (metaetiqueta) de desactivar el doble toque para hacer zoom. La mayoría de las dificultades se relacionan con esa interacción.

Puede detener pellizcar para hacer zoom con algo como esto:

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

Tenga en cuenta que si algún objetivo más profundo llama a stopPropagation en el evento, el evento no alcanzará el documento y este escucha no impedirá el comportamiento de escala.

Deshabilitar el doble toque para hacer zoom es similar. Deshabilita cualquier toque en el documento que ocurra dentro de los 300 milisegundos del toque anterior:

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

Si no configura correctamente los elementos de su formulario, al enfocar en una entrada se aplicará un zoom automático, y dado que en su mayoría ha desactivado el zoom manual, ahora será casi imposible quitar el zoom. Asegúrese de que el tamaño de la fuente de entrada sea> = 16px.

Si está tratando de resolver esto en un WKWebView en una aplicación nativa, la solución dada anteriormente es viable, pero esta es una mejor solución: https://stackoverflow.com/a/31943976/661418 . Y como se menciona en otras respuestas, en iOS 10 beta 6, Apple ahora ha proporcionado una bandera para honrar la metaetiqueta.

Actualización de mayo de 2017: reemplacé el antiguo método 'comprobar toques de longitud en el inicio táctil' para deshabilitar el pellizco-zoom con un enfoque más simple 'comprobar evento.escala en movimiento táctil'. Debería ser más confiable para todos.

Joseph
fuente
3
Tenga en cuenta que el hack de inicio táctil es inconsistente ... y si logra esquivarlo, está atrapado en un estado muy incómodo
Sam Saffron
55
P.ej. aplicaciones de mapeo a pantalla completa, hay una función de zoom codificada en la aplicación de mapeo (Google Maps JS, Leaflet, etc.). Google aconseja agregar una metaetiqueta <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />y si el navegador no respeta la metaetiqueta, es un diseño de navegador muy malo. El otro diseño muy malo es la acción de retroceso / avance deslizante, que no se puede evitar en iOS 9/10. Rompe severamente arrastrando acciones dentro de la aplicación web.
Timo Kähkönen
44
Si el usuario comienza a arrastrar con un dedo y luego coloca un segundo dedo en la pantalla, podrá pellizcar el zoom. Puede desactivar tanto el zoom como el desplazamiento con un preventDefaultencendido touchmove. No puede (completamente) deshabilitar el zoom sin deshabilitar el desplazamiento.
Paolo
10
Wow, esta parte (pegaré aquí) fue MUY útil para mí. No he visto esto mencionado por nadie más en CUALQUIER LUGAR en Internet. Me llevó horas solucionar este problema. Estoy realmente decepcionado con las opciones de diseño UX de Apple sobre esto, donde los formularios se acercan automáticamente pero luego no se alejan. 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
66
Parece que esto ya no funciona en iOS 12. ¿Alguna idea de cómo hacer que esto funcione para iOS 12?
TJR
78

Esta es una nueva característica en iOS 10.

De las notas de lanzamiento de iOS 10 beta 1:

  • Para mejorar la accesibilidad en los sitios web en Safari, los usuarios ahora pueden pellizcar para hacer zoom incluso cuando un sitio web se establece user-scalable=noen la ventana gráfica.

Espero que veamos un complemento JS pronto para deshabilitarlo de alguna manera.

Paul Gerarts
fuente
44
@Onza: No creo que sea malo. Creo que esta bien. Deshabilitar pellizcar / hacer zoom (comportamiento predeterminado del usuario) se considera malo, y muchos sitios web móviles lo hacen. El único caso de usuario aceptable sería una aplicación web real que se vea y se sienta como una aplicación.
wouterds
66
Malo. Cambio la vista usando js y bloqueo el zoom solo cuando se seleccionan algunos elementos en el sitio web ahora está roto debido a esta "decisión". Si alguien decide bloquearlo, hay una razón.
Zhenya
9
@Karlth es muy adecuado para un desarrollador de juegos
Sandeep
14
Tengo IOS 10.0.2, escalable por el usuario = no ya no deshabilita el zoom en nuestro sitio web ... Nuestro principal problema con el zoom es con nuestro menú lateral fijo ... Simplemente rompe el diseño ... ¿Alguna idea o solución al respecto? Entiendo que el zoom es bueno para la accesibilidad, lo hicimos disponible en partes específicas de nuestro sitio usando js events (hammer) y css ... No veo por qué una regla tiene que imponerse a todos, parece que la PC Police está comenzando para hacerse cargo de nuestro mundo de desarrollo también?
webkit
49
"El único caso de usuario aceptable sería una aplicación web real que se vea y se sienta como una aplicación". - y esto es, como usted ha dicho, un verdadero, caso de uso aceptable, que no es que rara ..
Florrie
21

He podido arreglar esto usando la touch-actionpropiedad css en elementos individuales. Intente configurar touch-action: manipulation;elementos en los que comúnmente se hace clic, como enlaces o botones.

iainbeeston
fuente
1
La "manipulación" no evita el zoom de pellizco, solo el zoom de doble toque.
Moos
44
Esta debería ser la respuesta aceptada. puedes usar touch-action: none;para controlar todos los gestos tú mismo.
Guy Sopher
3
esto es genial: deshabilitar el zoom de doble toque mientras se deja el pellizco de zoom, lo que DEBERÍA considerarse un gesto, no debería hacerlo el doble toque. 1 perro es un perro. 1 perro + 1 perro no hace una lanzadera espacial. Hace 2 perros, y hacen cosas que esperarías que hicieran 2 perros. Nunca esperé que 2 perros fueran un transbordador espacial. Nunca.
Larry
55
@GuySopher iOS notouch-action: none solo proporciona manipulatoin, lo que deja el problema de pellizco y zoom tal como está.
humanityANDpeace
14

Parece que este comportamiento supuestamente ha cambiado en la última versión beta, que al momento de escribir este artículo es beta 6.

De las notas de la versión para iOS 10 Beta 6:

WKWebViewahora por defecto respeta user-scalable=nodesde una ventana gráfica. Los clientes de WKWebViewpueden mejorar la accesibilidad y permitir a los usuarios pellizcar para hacer zoom en todas las páginas configurando la WKWebViewConfiguration propiedad ignoresViewportScaleLimitsen YES.

Sin embargo, en mis pruebas (muy limitadas), todavía no puedo confirmar que este sea el caso.

Editar: verificado, iOS 10 Beta 6 me respeta user-scalable=node manera predeterminada.

Cellane
fuente
11
10.0.1 aquí. No lo respeta. ¿Qué pasa con Apple deshaciéndose de las características que todos necesitan?
Lifwanian
1
Esto se refiere a WKWebView no a Safari. Fuente: Una de nuestras aplicaciones mapa se rompió y no tenemos ninguna idea de cómo solucionarlo.
Fabio Poloni
¡Ajá! Disculpas, vine aquí cuando buscaba la solución para el mismo error / función WKWebViewy supuse que la pregunta original se hacía WKWebViewal escribir mi respuesta. Así que supongo que durante una de las primeras versiones beta, Apple cambió el comportamiento de ambos WKWebViewy Safari móvil, luego en beta 6, revirtió el comportamiento de Safari, WKWebViewpero lo mantuvo.
Cellane
1
10.0.2 no respeta user-scalable=no. No estoy seguro de por qué alguna vez deshacerían esto, solo para recuperarlo, solo para eliminarlo nuevamente.
Aidan Hakimian
13

La solución que funciona en Safari Mobile en este momento de la escritura, es tener el tercer argumento a addEventListenersea { passive: false }, por lo que las miradas de solución completos como este:

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

Es posible que desee verificar si las opciones son compatibles para seguir siendo compatibles con versiones anteriores.

Casper Fabricius
fuente
3
¿Alguien intentó esto en iOS 12? Agregué el código anterior y no está haciendo nada para mi aplicación web. Todavía puedo hacer zoom en este estúpido Safari. Mi meta miradas etiqueta ventana como esta: por cierto <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">.
Patrick DaVader
1
@PatrickDaVader Sí, no puedo encontrar ninguna solución de trabajo para iOS 12 Safari. Mareada por todo el zoom incesante.
Jamie Birch
1
Este funciona en iOS 13. Mis etiquetas <meta> incluyen: <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, viewport-fit=cover, user-scalable=no, shrink-to-fit=no" />y<meta name="HandheldFriendly" content="true">
Sterling Bourne
1
@SterlingBourne Copió su configuración. Funciona, pero solo me gusta el 90% del tiempo. No estoy seguro de por qué no todo el tiempo.
Hillcow
1
¡La respuesta de @SterlingBourne funcionó para mí! Gracias. Debe publicarlo como una respuesta en lugar de un comentario para que pueda ser votado <meta name = "viewport" content = "width = device-width, initial-scale = 1, maximum-scale = 1, viewport-fit = cover, escalable por el usuario = no, contraíble = no "/> y <meta name =" HandheldFriendly "content =" true ">
Gene Black
8

Pasé aproximadamente una hora buscando una opción de JavaScript más robusta, y no encontré una. Da la casualidad de que en los últimos días he estado jugando con hammer.js (Hammer.js es una biblioteca que te permite manipular todo tipo de eventos táctiles fácilmente) y sobre todo fallando en lo que estaba tratando de hacer.

Con esa advertencia, y entendiendo que de ninguna manera soy un experto en JavaScript, esta es una solución que se me ocurrió que básicamente aprovecha hammer.js para capturar los eventos pinch-zoom y doble toque y luego registrarlos y descartarlos.

Asegúrese de incluir hammer.js en su página y luego intente pegar este javascript en la cabeza en alguna parte:

< 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
fuente
También he estado tratando de resolver este problema al trabajar con hammer.js, y puedo confirmar que podría evitar el zoom de la vista agregando .preventDefaulta todos los manejadores de gestos de martillo. Estoy usando deslizar / pellizcar / desplazar / tocar juntos, lo he agregado a todos los controladores, no sé si hay uno específico que esté haciendo el trabajo.
Conan
6

Intenté la respuesta anterior sobre pellizcar para hacer zoom

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

sin embargo, en algún momento la pantalla aún se amplía cuando event.touches.length> 1 descubrí que la mejor manera es usar el evento touchmove para evitar que se mueva un dedo en la pantalla. El código será algo como esto:

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

Espero que ayude.

Chihying Wu
fuente
77
Esto funciona solo si su aplicación es perfecta ... si tiene contenido desplazable, no funciona ... sigue siendo un buen truco para algunos escenarios.
eljamz
8
Esto incluso deshabilita el desplazamiento en el sitio web. MALO
Gags
@eljamz gracias por avisarme y sí ... mi aplicación se adapta perfectamente a la pantalla.
Chihying Wu
@Gags Todavía no probé la función de desplazamiento, gracias por avisarme.
Chihying Wu
6

Verifique el factor de escala en el evento táctil y luego evite el evento táctil.

document.addEventListener('touchmove', function(event) {
    event = event.originalEvent || event;
    if(event.scale > 1) {
        event.preventDefault();
    }
}, false);
Parmod
fuente
2
iOS 13 cambia false a {pasivo: falso}
wayofthefuture
6

Podemos obtener todo lo que queremos inyectando una regla de estilo e interceptando eventos 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)'
    }
  })
})

✔ Desactiva el zoom de pellizco.

✔ Desactiva el zoom de doble toque.

✔ El desplazamiento no se ve afectado.

✔ Desactiva el toque de resaltado (que se activa, en iOS, por la regla de estilo).

AVISO: modifique la detección de iOS a su gusto. Más sobre eso aquí .


Disculpas a lukejackson y Piotr Kowalski , cuyas respuestas aparecen en forma modificada en el código anterior.

jeff_mcmahan
fuente
Esto funciona en mi emulador de iPad que ejecuta iOS 11.2. En mi iPad real con iOS 11.3 no funciona. Agregué un console.log para asegurarme de que los eventos se activen y que aparezcan en la consola. ¿Tiene algo que ver con iOS 11.3? ¿O con dispositivos reales?
Mathieu R.
1
@MathieuR. Es un problema de iOS 11.3. Se puede rectificar utilizando una de las addEventListenerrespuestas basadas y pasando { passive: false }como optionsparámetro en lugar de false. Sin embargo, para la compatibilidad con versiones anteriores, debe pasar a falsemenos que el passivecampo de opción sea compatible. Ver developer.mozilla.org/en-US/docs/Web/API/EventTarget/…
Josh Gallagher
@JoshGallagher ¿Podría proporcionar un ejemplo de trabajo? En iOS11, ninguna de las respuestas funciona para mí.
Mick
El 'gesturestart' -> preventDefault funciona para mí al momento de escribir en iOS 12,2
Michael Camden
5

Se me ocurrió una solución bastante ingenua, pero parece funcionar. Mi objetivo era evitar que los doble toques accidentales se interpretaran como acercamiento, mientras mantenía el pellizco para hacer zoom trabajando para la accesibilidad.

La idea es medir el tiempo entre el primero touchstarty el segundo touchendcon un doble toque y luego interpretar el último touchendcomo un clic si el retraso es demasiado pequeño. Mientras evita el acercamiento accidental, este método parece mantener el desplazamiento de la lista sin verse afectado, lo cual es bueno. Sin embargo, no estoy seguro si no me he perdido nada.

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

Inspirado por una esencia de mutewinter y la respuesta de Joseph .

Alexander Kachkaev
fuente
5

En mi caso particular, estoy usando Babylon.js para crear una escena 3D y toda mi página consta de un lienzo de pantalla completa. El motor 3D tiene su propia funcionalidad de zoom, pero en iOS la pizca de zoom interfiere con eso. Actualicé la respuesta de @Joseph para superar mi problema. Para deshabilitarlo, descubrí que necesito pasar el {pasivo: falso} como una opción al oyente del evento. El siguiente código funciona para mí:

window.addEventListener(
    "touchmove",
    function(event) {
        if (event.scale !== 1) {
            event.preventDefault();
        }
    },
    { passive: false }
);
Hamed
fuente
Mi caso de uso también es una escena 3D de página completa con controles de pellizco personalizados. Me hubiera hundido si no hubiera una solución alternativa para Apple ignorando explícitamente la escala del usuario: no hay meta.
Nick Bilyk
1

Por extraño que parezca, al menos para Safari en iOS 10.2, tocar dos veces para hacer zoom está mágicamente desactivado si su elemento o alguno de sus antepasados ​​tiene uno de los siguientes:

  1. Un oyente onClick: puede ser un simple noop.
  2. Un cursor: pointerconjunto en CSS
mariomc
fuente
¿qué tal pellizcar?
Sam Su
Desafortunadamente, pellizcar para hacer zoom no está cubierto por esta solución. Para eso, utilizamos la solución propuesta en: stackoverflow.com/a/39594334/374196
mariomc
No funciona para mi Estoy usando 10.2.1 Beta 4 en un iPod Touch usando esta página de prueba y tocando dos veces cualquiera de los zooms de los cuadrados grises: jsbin.com/kamuta/quiet
robocat
1
Tengo esto en un lapso en una aplicación de reacción y no funciona.
FMD
1

El acercamiento involuntario tiende a ocurrir cuando:

  • Un usuario toca dos veces en un componente de la interfaz
  • Un usuario interactúa con la ventana gráfica utilizando dos o más dígitos (pellizcar)

Para evitar el comportamiento de doble toque , he encontrado dos soluciones muy simples:

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

Ambos evitan que Safari (iOS 10.3.2) amplíe el botón. Como puede ver, uno es solo JavaScript, el otro es solo CSS. Use apropiadamente.

Aquí hay una demostración: https://codepen.io/lukejacksonn/pen/QMELXQ

No he intentado evitar el comportamiento de pellizco (todavía), principalmente porque tiendo a no crear interfaces multitáctiles para la web y, en segundo lugar, he llegado a la idea de que quizás todas las interfaces, incluida la interfaz de usuario de la aplicación nativa, deberían ser "pellizcar para hacer zoom" -able en lugares. Todavía diseñaría para evitar que el usuario tenga que hacer esto para que su IU sea accesible para ellos, a toda costa.

lukejacksonn
fuente
1

Encontré este simple trabajo que parece evitar el doble clic para hacer zoom:

    // 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);
Sintaxis
fuente
1

Según lo solicitado, he transferido mi comentario a una respuesta para que la gente pueda votarlo:

Esto funciona el 90% del tiempo para 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" />

y

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

Sterling Bourne
fuente
0

Revisé todas las respuestas anteriores en la práctica con mi página en iOS (iPhone 6, iOS 10.0.2), pero sin éxito. Esta es mi solución de trabajo:

$(window).bind('gesturestart touchmove', function(event) {
    event = event.originalEvent || event;
    if (event.scale !== 1) {
         event.preventDefault();
         document.body.style.transform = 'scale(1)'
    }
});
Piotr Kowalski
fuente
Desafortunadamente, esto solo funciona cuando su página se ajusta perfectamente, no cuando tiene contenido desplazable
Shoe
Hmm Esto funciona bien con contenido desplazable, en mi experiencia (iOS 10.3).
jeff_mcmahan
0

esto funcionó para mí:

document.documentElement.addEventListener('touchmove', function (event) {
    event.preventDefault();
}, false);
Diego Santa Cruz Mendezú
fuente
Intenté esto, evitó el pellizco de zoom, sin embargo, deshabilita el desplazamiento táctil de la ventana gráfica para que no pueda desplazarse más por la página hacia arriba y hacia abajo.
TGR