desativar viewport com zoom no iOS 10+ safari?

164

Atualizei meu iPhone 6 plus para a versão beta do iOS 10 e acabei de descobrir que, no safari para celular, você pode ampliar qualquer página da web tocando duas vezes ou beliscando IGNORAR o user-scalable=nocódigo na metatag. Não sei se é um bug ou recurso. Se for considerado um recurso, como desativar a janela de visualização com zoom no safari do iOS 10?


atualizado na versão iOS 11/12, o safari iOS 11 e iOS 12 ainda NÃO respeita a user-scalable=nometatag.

site github móvel no Safari

Sam Su
fonte
2
Um recurso de acessibilidade:
Importante
87
Não é não. É uma prática ruim para o conteúdo normal da web. Para aplicativos da Web, o comportamento padrão do zoom pode arruinar completamente a usabilidade. Por exemplo, ninguém deseja aumentar o zoom em um botão de canal para cima porque o tocou duas vezes, nem aumentar parte de um videogame porque tocou no botão de salto duas vezes. Há uma razão pela qual esse recurso foi adicionado em primeiro lugar, e não faz sentido interromper a usabilidade para todos, apenas porque alguns "web designers" não sabem o que estão fazendo. Grite com os designers do site e pare de quebrar o navegador.
por dgatwood
36
Dizer que é "má prática" é uma opinião e não muda o fato de a Apple insistir em adotar padrões da Web que a comunidade gasta meses / anos / décadas sendo implementada em várias plataformas e dando uma grande importância a eles. Por que a Apple deve ditar que os web designers não sabem o que estão fazendo? Terrível argumento.
samrap
2
Pessoalmente, acho que isso decorre do código on-line, onde os desenvolvedores apenas copiam e colam cegamente, sem saber qual é o objetivo do código.
William isTed
7
A resposta é simples, Apple: torne a desativação da metatag uma configuração de acessibilidade padrão. Quem precisa, terá, sem punir quem não precisa.
Ruben Martinez Jr.

Respostas:

94

É possível impedir o dimensionamento de páginas da Web no safari no iOS 10, mas isso envolverá mais trabalho da sua parte. Acho que o argumento é que um certo grau de dificuldade deve impedir que os desenvolvedores de cultos de carga largem "user-scalable = no" em todas as tags de viewport e dificultem desnecessariamente as coisas para usuários com deficiência visual.

Ainda assim, eu gostaria que a Apple mudasse sua implementação para que houvesse uma maneira simples (meta-tag) de desativar o toque duplo no zoom. A maioria das dificuldades está relacionada a essa interação.

Você pode parar de beliscar para ampliar com algo assim:

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

Observe que, se algum destino mais profundo chamar stopPropagation no evento, o evento não alcançará o documento e o comportamento da escala não será impedido por esse ouvinte.

Desativar o toque duplo para ampliar é semelhante. Você desativa qualquer toque no documento que ocorre dentro de 300 milissegundos do toque anterior:

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

Se você não configurar corretamente os elementos do formulário, o foco em uma entrada será ampliado automaticamente e, como você desativou o zoom manual, agora será quase impossível descompactar. Verifique se o tamanho da fonte de entrada é> = 16px.

Se você está tentando resolver isso em um WKWebView em um aplicativo nativo, a solução fornecida acima é viável, mas é uma solução melhor: https://stackoverflow.com/a/31943976/661418 . E, como mencionado em outras respostas, no iOS 10 beta 6, a Apple agora forneceu uma bandeira para honrar a metatag.

Atualização em maio de 2017: substituí o antigo método 'check toches length on touchstart' de desativar o zoom de pitada por uma abordagem mais simples do 'check event.scale on touchmove'. Deve ser mais confiável para todos.

Joseph
fonte
3
Note-se que touchstart corte é inconsistente ... e se você conseguir contornar que você está preso em um estado muito desconfortável
Sam Saffron
5
Por exemplo. aplicativos de mapeamento em tela cheia, há um recurso de zoom codificado no aplicativo de mapeamento (Google Maps JS, Leaflet etc.). O Google aconselha a adicionar uma metatag <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />e, se o navegador não respeitar a metatag, o design do navegador será muito ruim. O outro, como um design muito ruim, é a ação de retroceder / avançar deslizando, o que não pode ser evitado no iOS 9/10. Ele quebra severamente as ações de arrastar dentro do aplicativo da web.
Timo Kähkönen 13/10
4
Se o usuário começar a arrastar com um dedo, coloque um segundo dedo na tela e poderá beliscar o zoom. Você pode desativar o zoom e rolar com um preventDefaultativado touchmove. Você não pode (completamente) desativar o zoom sem desativar a rolagem.
Paolo
10
Uau, essa parte (vou colar aqui) foi SUPER útil para mim. Eu não vi isso mencionado por mais ninguém em qualquer lugar na internet. Levei horas para corrigir esse problema. Estou realmente desapontado com as opções de design de UX da Apple sobre isso, onde o zoom é feito automaticamente, mas não diminui o zoom. 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
Parece que isso não está mais funcionando no iOS 12. Alguma idéia de como fazer isso funcionar no iOS 12?
TJR
78

Este é um novo recurso do iOS 10.

Nas notas de versão do iOS 10 beta 1:

  • Para melhorar a acessibilidade em sites no Safari, os usuários agora podem aumentar o zoom, mesmo quando um site é definido user-scalable=nona janela de exibição.

Espero que em breve vejamos um complemento JS para desativá-lo de alguma forma.

Paul Gerarts
fonte
4
@Onza: Eu não acho que é ruim. Eu acho que está bom. Desabilitar a pitada / zoom (comportamento padrão do usuário) é considerado ruim e muitos sites para celular fazem isso. O único caso de usuário aceitável seria um aplicativo Web real que se pareça com um aplicativo.
wouterds
6
Ruim .. Altero a janela de visualização usando js e bloqueio o zoom somente quando alguns elementos são selecionados no site, agora que estão quebrados devido a esta "decisão". Se alguém decidir bloqueá-lo - há uma razão.
Zhenya
9
@Karlth é muito cama para um desenvolvedor de jogos
Sandeep
14
Eu tenho o IOS 10.0.2, escalável pelo usuário = no não desabilita mais o zoom no nosso site ... Nosso principal problema com o zoom está no nosso menu lateral fixo. Ele apenas quebra o layout. Alguma idéia ou solução? Entendo que o zoom é bom para a acessibilidade, disponibilizamos o zoom em partes específicas do nosso site usando eventos js (hammer) e css. Não vejo por que uma regra deve ser imposta a todos, parece que o PC Police está começando para dominar o nosso mundo dev também ?!
webkit
49
"O único caso de usuário aceitável seria um aplicativo da Web real que se pareça com um aplicativo". - e esta é, como você disse, um caso de uso aceitável de verdade, que não é que raras ..
Florrie
21

Consegui consertar isso usando a touch-actionpropriedade css em elementos individuais. Tente definir touch-action: manipulation;elementos nos quais geralmente são clicados, como links ou botões.

iainbeeston
fonte
1
"manipulação" não impede o zoom de pitada, apenas toque duas vezes.
Moos
4
Essa deve ser a resposta aceita. você pode usar touch-action: none;para controlar todos os gestos.
precisa saber é o seguinte
3
isso é ótimo - desativar o zoom de toque duplo e deixar o zoom de pitada, o que DEVE ser considerado um gesto - o toque duplo não deve. 1 cachorro é um cachorro. 1 cão + 1 cão não faz um ônibus espacial. Faz 2 cães, e eles fazem coisas que você esperaria que 2 cães fizessem. Eu nunca esperava que dois cães fossem um ônibus espacial. Nunca.
Larry
5
O @GuySopher iOS não fornece touch-action: noneapenas manipulatoin, o que deixa o problema de pinch-zoom como está.
humanityANDpeace
14

Parece que esse comportamento foi supostamente alterado na versão beta mais recente, que no momento da redação é a versão 6.

Nas notas de versão do iOS 10 Beta 6:

WKWebViewagora o padrão é respeitar a user-scalable=nopartir de uma viewport. Clientes de WKWebViewpode melhorar a acessibilidade e permitir que os usuários de beliscar-a-zoom em todas as páginas, definindo a WKWebViewConfiguration propriedade ignoresViewportScaleLimitspara YES.

No entanto, nos meus testes (muito limitados), ainda não posso confirmar que este é o caso.

Editar: verificado, o iOS 10 Beta 6 respeita user-scalable=nopor padrão para mim.

Cellane
fonte
11
10.0.1 aqui. Não o respeita. O que é com a Apple se livrar de características que as necessidades de todos ..
lifwanian
1
Isso se refere a WKWebView não o Safari. Fonte: Um dos nossos aplicativos de mapas quebrou e não temos nenhuma idéia de como corrigi-lo.
Fabio Poloni #
Aha! Desculpas, eu vim aqui ao procurar a solução para o mesmo bug / recurso WKWebViewe meio que assumi que a pergunta original era perguntada WKWebViewao escrever minha resposta. Portanto, suponho que durante uma das primeiras versões beta, a Apple alterou o comportamento do WKWebViewSafari móvel e, em seguida, no beta 6, eles reverteram o comportamento do, WKWebViewmas o mantiveram para o Safari móvel.
Cellane 29/09/16
1
10.0.2 não respeita user-scalable=no. Não sei por que eles desfizeram isso, apenas para trazê-lo de volta, apenas para removê-lo novamente.
Aidan Hakimian
13

A solução que funciona em Mobile Safari no momento da escrita, é ter o terceiro argumento a addEventListenerseja { passive: false }, de modo a aparência de solução completa como este:

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

Convém verificar se há opções compatíveis para permanecer compatível com versões anteriores.

Casper Fabricius
fonte
3
Alguém tentou isso no iOS 12? Eu adicionei o código acima e ele não está fazendo nada para o meu webapp. Ainda é possível ampliar esse estúpido Safari. Meus meta tag viewport olhares como este btw: <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">.
Patrick DaVader 24/10
1
@PatrickDaVader Sim, não consigo encontrar nenhuma solução para o iOS 12 Safari. Ficar enjoado com todo o zoom incessante.
Jamie Birch
1
Este funciona no iOS 13. Minhas tags <meta> incluem: <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, viewport-fit=cover, user-scalable=no, shrink-to-fit=no" />e<meta name="HandheldFriendly" content="true">
Sterling Bourne
1
@SterlingBourne Copiou sua configuração. Funciona, mas apenas 90% das vezes. Não sei por que não o tempo todo.
Hillcow 12/11/19
1
A resposta @SterlingBourne funcionou para mim! Obrigado. Ele deve publicá-lo como resposta, e não como comentário, para que possa ser votado. <Meta name = "viewport" content = "width = largura do dispositivo, escala inicial = 1, escala máxima = 1, ajuste da viewport = capa, user-scalable = no, encolher para ajustar = no "/> e <meta name =" HandheldFriendly "content =" true ">
Gene Black
8

Passei cerca de uma hora procurando uma opção javascript mais robusta e não encontrei uma. Acontece que, nos últimos dias, estive brincando com o hammer.js (Hammer.js é uma biblioteca que permite manipular todos os tipos de eventos de toque com facilidade) e falhando principalmente com o que eu estava tentando fazer.

Com essa ressalva, e entendendo que eu não sou especialista em javascript, esta é uma solução que eu criei que basicamente utiliza o hammer.js para capturar os eventos de pinch-zoom e toque duas vezes e depois registrá-los e descartá-los.

Certifique-se de incluir hammer.js em sua página e tente colocar esse javascript na cabeça em algum lugar:

< 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
fonte
Também tentei resolver esse problema ao trabalhar com o hammer.js e posso confirmar que eu poderia impedir o zoom da viewport adicionando a .preventDefaulta todos os manipuladores de gesto do martelo. Estou usando furto / pitada / panela / torneira juntos, adicionei a todos os manipuladores, não sei se há um específico que esteja fazendo o trabalho.
Conan
6

Eu tentei a resposta anterior sobre pitada de zoom

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

no entanto, em algum momento a tela ainda é ampliada quando o evento.touches.length> 1 Eu descobri a melhor maneira de usar o evento touchmove, para evitar qualquer movimento do dedo na tela. O código será algo como isto:

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

Espero que ajude.

Chihying Wu
fonte
7
Isso funciona apenas se o seu aplicativo é um ajuste perfeito ... se você tem conteúdo rolável, ele não funciona ... ainda é um truque agradável para alguns cenários.
eljamz
8
Isso até desabilita a rolagem no site. BAD
Gags
@ eljamz obrigado por me avise e sim ... meu aplicativo é o ajuste perfeito na tela.
Chihying Wu
@ Gags Ainda não testei a função de rolagem, obrigado por me avisar.
Chihying Wu
6

Verifique o fator de escala no evento touchove e evite o evento touch.

document.addEventListener('touchmove', function(event) {
    event = event.originalEvent || event;
    if(event.scale > 1) {
        event.preventDefault();
    }
}, false);
Parmod
fonte
2
Alteração do iOS 13 false para {passive: false} #
wayofthefuture
6

Podemos obter tudo o que queremos injetando uma regra 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)'
    }
  })
})

✔ Desativa o zoom de pitada.

✔ Desativa o toque duplo do zoom.

✔ A rolagem não é afetada.

✔ Desativa o toque em destaque (que é acionado, no iOS, pela regra de estilo).

AVISO: ajuste a detecção do iOS ao seu gosto. Mais sobre isso aqui .


Desculpas a lukejackson e Piotr Kowalski , cujas respostas aparecem na forma modificada no código acima.

jeff_mcmahan
fonte
Isso funciona no meu emulador de iPad que está executando o iOS 11.2. No meu iPad real, executando o iOS 11.3, ele não funciona. Adicionei um console.log para garantir que os eventos sejam disparados e que apareçam no console. Tem algo a ver com o iOS 11.3? Ou com dispositivos reais?
Mathieu R.
1
@MathieuR. É uma questão do iOS 11.3. Pode ser corrigido usando uma das addEventListenerrespostas baseadas e passando { passive: false }como optionsparâmetro em vez de false. No entanto, para compatibilidade com versões anteriores, você precisa passar false, a menos que o passivecampo de opção seja suportado. Veja developer.mozilla.org/pt-BR/docs/Web/API/EventTarget/…
Josh Gallagher
@JoshGallagher Você poderia dar um exemplo de trabalho? No iOS11, nenhuma das respostas está funcionando para mim.
Mick
O 'gesturestart' -> preventDefault funciona para mim no momento em que escrevo no iOS 12,2
Michael Camden
5

Eu vim com uma solução bastante ingênua, mas parece funcionar. Meu objetivo era impedir que os toques duplos acidentais fossem interpretados como aumentar o zoom, mantendo a pressão para aumentar o zoom para garantir a acessibilidade.

A idéia é medir o tempo entre o primeiro touchstarte o segundo touchendem um toque duplo e depois interpretar o último touchendcomo clique, se o atraso for muito pequeno. Embora evite o zoom acidental, esse método parece manter a rolagem da lista inalterada, o que é bom. Não tenho certeza se não perdi 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 uma essência de mutewinter e a resposta de Joseph .

Alexander Kachkaev
fonte
5

No meu caso particular, estou usando o Babylon.js para criar uma cena 3D e toda a minha página consiste em uma tela em tela cheia. O mecanismo 3D tem sua própria funcionalidade de zoom, mas no iOS a pressão do zoom interfere nisso. Atualizei a resposta @ Joseph para superar meu problema. Para desativá-lo, descobri que preciso passar o {passive: false} como uma opção para o ouvinte de eventos. O código a seguir funciona para mim:

window.addEventListener(
    "touchmove",
    function(event) {
        if (event.scale !== 1) {
            event.preventDefault();
        }
    },
    { passive: false }
);
Hamed
fonte
Meu caso de uso também é uma cena 3D de página inteira com controles personalizados de pitada. Eu teria ficado afundado se não houvesse uma solução alternativa para a Apple ignorar explicitamente a escala do usuário: sem meta.
precisa saber é o seguinte
1

Por mais estranho que pareça, pelo menos para o Safari no iOS 10.2, toque duas vezes para ampliar será desativado magicamente se o seu elemento ou qualquer um de seus ancestrais tiver um dos seguintes:

  1. Um ouvinte onClick - pode ser um noop simples.
  2. Um cursor: pointerconjunto em CSS
mariomc
fonte
que tal beliscar?
Sam Su
Infelizmente, beliscar para ampliar não é coberto por esta solução. Para isso, usamos a solução proposta em: stackoverflow.com/a/39594334/374196
mariomc
Não funciona para mim. Estou usando o 10.2.1 Beta 4 em um iPod Touch usando esta página de teste e tocando duas vezes em qualquer um dos quadrados cinza: jsbin.com/kamuta/quiet
robocat
1
Eu tenho isso em um intervalo em um aplicativo de reação e ele não funciona.
FMD
1

O zoom não intencional tende a acontecer quando:

  • Um usuário toca duas vezes em um componente da interface
  • Um usuário interage com a viewport usando dois ou mais dígitos (pitada)

Para impedir a comportamento de toque duplo , encontrei duas soluções simples:

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

Ambos impedem o Safari (iOS 10.3.2) de aumentar o zoom no botão. Como você pode ver, um é apenas JavaScript, o outro é apenas CSS. Use apropriadamente.

Aqui está uma demonstração: https://codepen.io/lukejacksonn/pen/QMELXQ

Ainda não tentei impedir o comportamento de pitada, principalmente porque não costumo criar interfaces de toque múltiplo para a Web e, em segundo lugar, cheguei à ideia de que talvez todas as interfaces, incluindo a interface do usuário do aplicativo nativo, devam ser "pitada de zoom" -able em alguns lugares. Eu ainda projetar para evitar que o usuário ter que fazer isso para tornar a sua interface acessível a eles, a todo o custo.

lukejacksonn
fonte
1

Encontrou este trabalho simples em torno do qual parece impedir o clique duplo para aumentar o 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);
Sintaxe
fonte
1

Conforme solicitado, transferi meu comentário para uma resposta, para que as pessoas possam votar novamente:

Isso funciona 90% do tempo para o 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" />

e

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

Sterling Bourne
fonte
0

Verifiquei todas as respostas acima na prática com minha página no iOS (iPhone 6, iOS 10.0.2), mas sem sucesso. Esta é a minha solução de trabalho:

$(window).bind('gesturestart touchmove', function(event) {
    event = event.originalEvent || event;
    if (event.scale !== 1) {
         event.preventDefault();
         document.body.style.transform = 'scale(1)'
    }
});
Piotr Kowalski
fonte
Infelizmente, isso só funciona quando sua página é perfeita, não quando você tem conteúdo rolável #
Shoe #:
Hmm. Isso funciona bem com conteúdo rolável, na minha experiência (iOS 10.3).
jeff_mcmahan
0

isso funcionou para mim:

document.documentElement.addEventListener('touchmove', function (event) {
    event.preventDefault();
}, false);
Diego Santa Cruz Mendezú
fonte
Eu tentei isso, impediu o zoom de pitada, no entanto, desabilita a rolagem sensível ao toque da janela de exibição para que você não possa mais rolar a página para cima e para baixo.
TGR 14/06