Desativar o zoom automático na tag "Texto" de entrada - Safari no iPhone

540

Eu criei uma página HTML com uma <input>tag type="text". Quando clico nele usando o Safari no iPhone, a página fica maior (zoom automático). Alguém sabe como desativar isso?

Eduardo Montenegro
fonte
8
Para todos os usuários do Twitter Bootstrap que chegam aqui: consulte também esta questão do Github .
Jeroen
7
Eu acho que a resposta da @daxmacrog responde exatamente o que você quer, você está disposto a aceitá-la para que ela suba ao topo e economize muito retrabalho das pessoas que estão lendo tudo isso? Resposta 2018: stackoverflow.com/a/46254706/172651
Evolve
@ Evolua a resposta que você falou sobre quebra a funcionalidade de pitada e zoom do Android. resposta daxmacrog é falho.
MH
4
Eu juro, a Apple cria esses anti-recursos apenas para mexer com nossas cabeças.
Andrew Koster
@AndrewKoster, eu concordo com você agora mesmo em 2020.
Ashok

Respostas:

492

O navegador aumentará o zoom se o tamanho da fonte for menor que 16pxe o tamanho da fonte padrão para os elementos do formulário for 11px(pelo menos no Chrome e Safari).

Além disso, o selectelemento precisa ter a focuspseudo classe anexada.

input[type="color"],
input[type="date"],
input[type="datetime"],
input[type="datetime-local"],
input[type="email"],
input[type="month"],
input[type="number"],
input[type="password"],
input[type="search"],
input[type="tel"],
input[type="text"],
input[type="time"],
input[type="url"],
input[type="week"],
select:focus,
textarea {
  font-size: 16px;
}

Não é necessário o uso de todos os acima, você pode simplesmente estilo os elementos que você precisa, por exemplo: apenas text, numbere textarea:

input[type='text'],
input[type='number'],
textarea {
  font-size: 16px;
}

Solução alternativa para herdar os elementos de entrada de um estilo pai:

body {
  font-size: 16px;
}
input[type="text"] {
  font-size: inherit;
}
srikanth
fonte
81
Só para ter tudo coberto: select, textarea, input[type="text"], input[type="password"], input[type="datetime"], input[type="datetime-local"], input[type="date"], input[type="month"], input[type="time"], input[type="week"], input[type="number"], input[type="email"], input[type="url"], input[type="search"], input[type="tel"], input[type="color"] { font-size: 16px; }
Nic Barbier
8
@ Nic Você precisa usar select:focus. Estava tendo o mesmo problema também.
precisa saber é
141
Eu não entendo, como isso é uma correção? E se eu quiser um tamanho de fonte menor / maior?
Bryan
47
A maneira correta é alterar a meta tag para: <meta name = "viewport" content = "width = largura do dispositivo, escala inicial = 1, escala máxima = 1, escalável pelo usuário = 0" />
Milos Matic
37
@MilosMatic Na maioria dos casos, provavelmente não é uma boa solução, pois impede completamente o usuário de dimensionar a página. Potencialmente ainda mais irritante para seus visitantes.
BadHorsie
362

Você pode impedir que o Safari faça zoom automaticamente nos campos de texto durante a entrada do usuário sem desativar a capacidade do usuário de beliscar o zoom. Basta adicionarmaximum-scale=1 mas deixar de fora o atributo de escala do usuário sugerido em outras respostas.

É uma opção interessante se você tiver um formulário em uma camada que "flutue" ao redor se for ampliada, o que pode fazer com que elementos importantes da interface do usuário se movam para fora da tela.

<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">

daxmacrog
fonte
65
Esta é a solução 2018+. Voto positivo como se sua vida dependesse disso.
Henrik Petterson
17
Isso vai quebrar dispositivos android capacidade de zoom
fen1ksss
4
@daxmacrog, você está certo, mas o OP não mencionou se ele quer quebrar os andróides, permitindo o comportamento necessário. Foi aqui que pessoalmente tomei a opção incorreta. Claro, é melhor especificar.
fen1ksss
13
@HenrikPetterson Isso faz mais do que desabilitar o zoom automático, conforme especificado pelo OP, mas também desabilita o zoom de pitada. Portanto, não acho que seja a solução 2018+.
André Werlang
4
@ AndréWerlang Isso não é exato. Como indicado claramente na resposta, esta solução não desativa o zoom de pitada no Safari (ou Firefox), que é o que o OP perguntou. Mas, como apontado nos comentários anteriores, ele desabilita o zoom do usuário em dispositivos Android e no Chrome no iOS.
Daxmacrog 18/09/19
223
@media screen and (-webkit-min-device-pixel-ratio:0) { 
  select:focus,
  textarea:focus,
  input:focus {
    font-size: 16px;
    background: #eee;
  }
}

Novo: o IOS ainda ampliará, a menos que você use 16px na entrada sem o foco.

@media screen and (-webkit-min-device-pixel-ratio:0) { 
  select,
  textarea,
  input {
    font-size: 16px;
  }
}

Eu adicionei um plano de fundo, já que o IOS não adiciona plano de fundo ao selecionar.

Christina
fonte
9
Isso funciona não apenas para o safari no iOS (iphone / ipad / ipod), mas também para o Safari / OSX e o Chrome (windows e Mac). Portanto, se você estiver tentando segmentar especificamente o iphone, isso não funcionará.
Redtopia
31
Por que todo mundo está dizendo 16px, mas ninguém se importa em mencionar exatamente porque é 16px? Por que um número tão arbitrário? Por que precisamos definir o tamanho do texto do campo de formulário para 16px e não .. digamos 1.8rem ou 2.5em ou algo assim? Isso é apenas um bug estúpido de um sistema operacional proprietário?
Beebee 14/07
14
O tamanho da fonte @Beebee 100% é 16px, o padrão para a maioria, se não todos os navegadores (também para a área de trabalho). O IOS usa isso como padrão provavelmente porque é um tamanho confortável para leitura. Por que está definido dessa maneira, eu não me incomodei em olhar para cima, não me importo.
Christina
5
Use @media screen and (-webkit-min-device-pixel-ratio:0) and (max-device-width:1024px)para limitar o efeito ao iPhone, mas não modifique sites quando visualizados no Chrome.
BurninLeo
9
Em vez de usar uma consulta de mídia, você deve usar @supports (-webkit-overflow-scrolling: touch), como este recurso css só existe no iOS
James Moran
189

Se o seu site for projetado corretamente para um dispositivo móvel, você poderá decidir não permitir o dimensionamento.

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />

Isso resolve o problema que a sua página ou formulário para celular vai 'flutuar'.

Marcellino Bommezijn
fonte
123
Tecnicamente correto, mas não concordo com o raciocínio. Desabilitar o zoom do usuário em um site projetado adequadamente ainda é uma má idéia.
Fer
20
"Projetado adequadamente" é muito subjetivo. Considere um cabeçalho fixo de 50 px na parte superior de um site que seja totalmente responsivo e deve funcionar em todos os navegadores. O zoom no iOS Safari quebra o posicionamento do cabeçalho e praticamente quebra o site inteiro.
Redtopia
62
Desabilitar o recurso de zoom do usuário é uma prática terrível da perspectiva do UX e deve ser realmente evitada a todo custo. A capacidade de ampliar livremente é um recurso básico de acessibilidade e um controle que você nunca deve tirar do usuário.
Gabriel Luethje 21/01
72
Nos aplicativos móveis nativos, você nunca tem a chance de aumentar o zoom e eles funcionam muito bem, por que um aplicativo da web seria diferente? Se você definir o tamanho da fonte e a altura da linha apropriados, com contrastes claros, deverá estar bem.
precisa saber é o seguinte
39
Aqueles que usam o argumento 'está bom em aplicativos nativos' estão negligenciando o fato de que aplicativos nativos bem elaborados aderem às configurações de acessibilidade no nível do sistema operacional, como tamanho do texto. Usuários mais velhos e com deficiência visual podem e usam tamanhos de fonte extremamente grandes em todo o sistema operacional porque precisam . Os aplicativos da Web geralmente não seguem ou não podem aderir a essa configuração, portanto, é vital que a funcionalidade de acessibilidade interna do navegador da Web, como o zoom, seja vital. Tudo o que você acha que é perfeitamente legível, acredite, há pessoas que não o acharão suficientemente claro. Você não tomar essa opção longe de usuários se você valoriza a usabilidade.
Ryan Williams
72

Em resumo, a resposta é: defina o tamanho da fonte dos elementos do formulário para pelo menos 16 px

Nik
fonte
Sim, essa é definitivamente a melhor prática para evitar o zoom em dispositivos móveis. Sem js, sem hacks, sem soluções alternativas. Mas mesmo com 16px eu notei um zoom muito pequeno nas minhas páginas, então tentei 17px, 18px ... para ver o que acontece.
Ed1nh0
8
É uma prática recomendada declarar 100% no corpo, botão, entrada, área de texto e selecionar elementos. Isso permite que o usuário defina um padrão que não seja o 16px enviado com os navegadores. Alguém que tenha problemas para ler na tela pode definir o padrão como 18 ou 20 pixels. Você não deseja substituir a escolha deles forçando 16px neles. No entanto, no que diz respeito ao iOS, eles tomaram a decisão de aumentar qualquer valor que, segundo o HIG, seja muito pequeno. Infelizmente, parece que ele não interpreta o valor de 100%, por isso não podemos adicionar o padrão para apaziguar.
J. Hogue
RE iOS Safari, a partir deste comentário, parece que o Safari interpreta corretamente o font-size: 100%valor e obtém os 16px necessários.
Nathan Lafferty
36
input[type='text'],textarea {font-size:1em;}
stormsweeper
fonte
3
Observe que definir escalável pelo usuário como não desativará todo o zoom, o que provavelmente é uma má ideia.
stormsweeper
18
Isso funciona apenas se o tamanho da fonte do seu corpo for o padrão (não especificado, ou 1em, ou 100%). Se você definir um tamanho de fonte personalizado, poderá defini-lo font-sizeno snippet 16pxpara evitar o zoom automático.
Alan H.
Sei que essa pergunta foi direcionada ao iPhone, mas é mais compatível entre plataformas e no futuro de mais plataformas / dispositivos. Tentei a abordagem 16px, mas em um tablet Android reduzi apenas o efeito de zoom automático. A configuração para '1em', conforme especificado na postagem, resolveu o problema.
toddles_fp
3
Nem 1emnem 1remé uma solução adequada, porque tanto pode ser inferior 16pxe Safari requer pelo menos 16pxpara não ampliar.
Finesse
2
i utilizado solução janela, mas não funcionou, 16px solução é funciona bem, mas 16px é grande demais para inputbox do meu site, há tem qualquer 3ª solução
Suneth Kalhara
21

A maneira correta de corrigir esse problema é alterar a meta viewport para:

<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0"/>

Milos Matic
fonte
32
Essa não é necessariamente a maneira "adequada" de impedir esse comportamento. O Mobile Safari aumenta o zoom se o texto for considerado pequeno demais para ser lido. Desativar o zoom em conjunto é pesado e impede que os usuários possam interagir com sua página da maneira que eles esperam.
precisa saber é o seguinte
3
Aparentemente, no iOS10, a Apple alterou a propriedade de escala máxima para não ser mais respeitada, permitindo que todos os sites aumentassem o zoom independentemente da configuração.
Wolfr
3
Isso funciona para a versão iOS10 20 / setembro / 2016 ... pelo menos funciona no meu aplicativo ... Obrigado !!! Antes de usar <meta name = "viewport" content = "width = largura do dispositivo, escala inicial = 1, escala mínima = 1 , escala máxima = 1"> Mas eu mudei para a linha na resposta e funcionou ...
eljamz 22/09
1
"Verifique se o zoom de pitada do navegador não está bloqueado pelo meta-elemento da janela de exibição da página, para que possa ser usado para aumentar o zoom da página em 200%. Devem ser evitados valores restritivos para atributos escaláveis ​​pelo usuário e em escala máxima desse meta-elemento." w3.org/TR/mobile-accessibility-mapping/#zoom-magnification #
danielnixon
Vi comentários sobre como algumas dessas metatags não funcionam no iOS 10 e eu sei que as opções acima funcionam no Chrome para iOS pelo menos. :) Obrigado!
precisa saber é o seguinte
16

Não há uma maneira limpa de encontrar, mas aqui está um truque ...

1) Notei que o evento do mouseover ocorre antes do zoom, mas o zoom ocorre antes dos eventos de redução ou foco.

2) Você pode alterar dinamicamente a tag da porta de visualização META usando javascript (consulte Ativar / desativar o zoom no safari do iPhone com Javascript? )

Então, tente isso (mostrado no jquery para compactação):

$("input[type=text], textarea").mouseover(zoomDisable).mousedown(zoomEnable);
function zoomDisable(){
  $('head meta[name=viewport]').remove();
  $('head').prepend('<meta name="viewport" content="user-scalable=0" />');
}
function zoomEnable(){
  $('head meta[name=viewport]').remove();
  $('head').prepend('<meta name="viewport" content="user-scalable=1" />');
}

Definitivamente, isso é um hack ... pode haver situações em que o mouse / down nem sempre captura entradas / saídas, mas funcionou bem nos meus testes e é um começo sólido.

dlo
fonte
5
Não tenho certeza de quando o comportamento do Safari pode ter sido alterado, mas agora a remoção do mouse (iOS6.0.1) está ocorrendo antes do zoom automático. Assim, na minha solução anterior, o zoom está sendo reativado cedo demais. Não encontrei uma correção adequada, pois todos os eventos que experimentei agora acontecem antes do zoom. Você pode reativar o zoom com uma tecla pressionada ou um borrão, mas há alguns cenários que podem ser perdidos (como se o usuário desejasse aumentar o zoom manualmente antes de começar a digitar qualquer coisa).
dlo
15

Adicione user-scalable = 0 para a viewport meta da seguinte maneira

<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=0">

Trabalhou para mim :)

Tuyen Cao
fonte
11
"Verifique se o zoom de pitada do navegador não está bloqueado pelo meta-elemento da janela de exibição da página, para que possa ser usado para aumentar o zoom da página em 200%. Devem ser evitados valores restritivos para atributos escaláveis ​​pelo usuário e em escala máxima desse meta-elemento." w3.org/TR/mobile-accessibility-mapping/#zoom-magnification #
danielnixon
9
Isso quebra as regras de acessibilidade definidas pelo W3.
Joshua Russell
trabalhou para mim, também esta é a melhor solução para mim como eu quero a liberdade para tamanhos de fonte de entrada de mudança abaixo 16px e não querem um hack JS
azul Bot
14

Recentemente (hoje: D) tive que integrar esse comportamento. Para não impactar os campos de design originais, incluindo o combo, optei por aplicar a transformação no foco do campo:

input[type="text"]:focus, input[type="password"]:focus,
textarea:focus, select:focus {
  font-size: 16px;
}
piouPiouM
fonte
Para sua informação, isso funcionou bem no meu iphone 5 com iOS 6, mas em um iphone 4 com iOS 5 no modo retrato, o estilo do foco foi aplicado depois que o zoom ocorreu. Talvez algo sutil esteja acontecendo, eu não investiguei mais.
Vish
Eu só quero dizer que eu tenho lotes de diferentes consultas usando zoom para o desenvolvimento make ir mais rápido e dependendo de quanto você aumenta o zoom irá determinar o quanto font-size que você precisa Eu acredito
mike
: focus não funcionou para mim iOS 10.2 iPhone 6, mas input [type = "text"]: hover funcionou bem.
Amirhossein RZD
13

Como muitas outras respostas já apontaram, isso pode ser alcançado adicionando maximum-scaleà metatag viewport. No entanto, isso tem a consequência negativa de desativar o zoom do usuário em dispositivos Android . ( Não desativa o zoom do usuário em dispositivos iOS desde a v10 .)

Podemos usar JavaScript para adicionar dinamicamente maximum-scaleà meta viewportquando o dispositivo é iOS. Isso alcança o melhor dos dois mundos: permitimos que o usuário amplie e evite que o iOS amplie os campos de texto em foco.

| maximum-scale             | iOS: can zoom | iOS: no text field zoom | Android: can zoom |
| ------------------------- | ------------- | ----------------------- | ----------------- |
| yes                       | yes           | yes                     | no                |
| no                        | yes           | no                      | yes               |
| yes on iOS, no on Android | yes           | yes                     | yes               |

Código:

const addMaximumScaleToMetaViewport = () => {
  const el = document.querySelector('meta[name=viewport]');

  if (el !== null) {
    let content = el.getAttribute('content');
    let re = /maximum\-scale=[0-9\.]+/g;

    if (re.test(content)) {
        content = content.replace(re, 'maximum-scale=1.0');
    } else {
        content = [content, 'maximum-scale=1.0'].join(', ')
    }

    el.setAttribute('content', content);
  }
};

const disableIosTextFieldZoom = addMaximumScaleToMetaViewport;

// /programming/9038625/detect-if-device-is-ios/9039885#9039885
const checkIsIOS = () =>
  /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;

if (checkIsIOS()) {
  disableIosTextFieldZoom();
}
Oliver Joseph Ash
fonte
Por que você cria uma cópia addMaximumScaleToMetaViewport? É apenas por razões semânticas?
Pherrymason 18/09/19
Sim, basta mapear a função para um nome diferente, para que fique claro como está sendo usada.
Oliver Joseph Ash
8

Hack de Javascript, que funciona no iOS 7. Isso é baseado na resposta do @dlo, mas os eventos de mouseover e mouseout são substituídos pelos eventos touchstart e touchend. Basicamente, esse script adiciona um intervalo de meio segundo antes que o zoom seja ativado novamente para impedir o zoom.

$("input[type=text], textarea").on({ 'touchstart' : function() {
    zoomDisable();
}});
$("input[type=text], textarea").on({ 'touchend' : function() {
    setTimeout(zoomEnable, 500);
}});

function zoomDisable(){
  $('head meta[name=viewport]').remove();
  $('head').prepend('<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0" />');
}
function zoomEnable(){
  $('head meta[name=viewport]').remove();
  $('head').prepend('<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=1" />');
} 
Ilkka R.
fonte
Isso funcionou melhor para mim. Mas mudei os eventos touchstart / touchend para um evento de 'foco' com zoomDisable e zoomEnable.
11603 Justin Cloud
Adicionar o atraso parece funcionar muito bem nas versões mais recentes do iOS, mas é interessante que ele não funcione muito bem quando definido para 250ms. Isso sugere que, em algumas circunstâncias, 500ms também podem não funcionar, mas se funcionar na maioria das vezes, acho que é melhor do que não funcionar. Bem pensado.
dlo
7

Isso funcionou para mim:

input, textarea {
    font-size: initial;
}

fonte
Bem simples, mas existe alguma maneira de controlar qual é esse tamanho "inicial"?
2540625
Não testei, mas essa deve ser uma maneira de controlar o tamanho da fonte. (informe-me se isso funcionar e eu atualizarei minha resposta) body {font-size: 20px; } entrada {tamanho da fonte: herdar; }
7

Usei a solução de Christina acima, mas com uma pequena modificação para o bootstrap e outra regra para aplicar aos computadores de mesa. O tamanho da fonte padrão do Bootstrap é 14px, o que causa o zoom. O seguinte altera para 16px para "controles de formulário" no Bootstrap, impedindo o zoom.

@media screen and (-webkit-min-device-pixel-ratio:0) {
  .form-control {
    font-size: 16px;
  }
}

E voltando ao 14px para navegadores não móveis.

@media (min-width: 768px) {
  .form-control {
    font-size: 14px;
  }
}

Tentei usar o .form-control: focus, que o deixou em 14px, exceto no foco, que foi alterado para 16px e não corrigiu o problema de zoom no iOS8. Pelo menos no meu iPhone usando iOS8, o tamanho da fonte deve ser 16 px antes do foco para o iPhone não ampliar a página.

Tanny O'Haley
fonte
6

Eu fiz isso, também com jQuery:

$('input[type=search]').on('focus', function(){
  // replace CSS font-size with 16px to disable auto zoom on iOS
  $(this).data('fontSize', $(this).css('font-size')).css('font-size', '16px');
}).on('blur', function(){
  // put back the CSS font-size
  $(this).css('font-size', $(this).data('fontSize'));
});

Obviamente, alguns outros elementos na interface podem precisar ser adaptados se esse 16pxtamanho da fonte interromper o design.

Nicolas Hoizey
fonte
4
Isso é elegante. Isso é estiloso. Estou sem trocadilhos. Abordagem inteligente.
crowjonah
@Wolfr você experimentou um dispositivo real?
Nicolas Hoizey
1
Isso funcionou para nós no iOS 12. Eu gosto mais dessa abordagem, em vez de mexer com transformações de CSS e margens negativas.
anonymous-one
6

Depois de um tempo tentando, eu vim com esta solução

// set font-size to 16px to prevent zoom 
input.addEventListener("mousedown", function (e) {
  e.target.style.fontSize = "16px";
});

// change font-size back to its initial value so the design will not break
input.addEventListener("focus", function (e) {
  e.target.style.fontSize = "";
});

Em "mousedown", define o tamanho da fonte da entrada como 16px. Isso impedirá o zoom. No evento de foco, ele altera o tamanho da fonte de volta ao valor inicial.

Diferentemente das soluções publicadas anteriormente, isso permitirá que você defina o tamanho da fonte da entrada para o que quiser.

jirikuchta
fonte
Este realmente funciona para mim, especialmente porque nas versões mais recentes do iOS você não pode usar a metatag viewport para desativar o zoom.
precisa saber é o seguinte
Confirmado que trabalham no iOS 12.1, graças
Ziki
6

Depois de ler quase todas as linhas aqui e testar as várias soluções, é isso, graças a todos que compartilharam suas soluções, o que eu criei, testei e trabalhei para mim no iPhone 7 iOS 10.x:

@media screen and (-webkit-min-device-pixel-ratio:0) {
    input[type="email"]:hover,
    input[type="number"]:hover,
    input[type="search"]:hover,
    input[type="text"]:hover,
    input[type="tel"]:hover,
    input[type="url"]:hover,
    input[type="password"]:hover,
    textarea:hover,
    select:hover{font-size: initial;}
}
@media (min-width: 768px) {
    input[type="email"]:hover,
    input[type="number"]:hover,
    input[type="search"]:hover,
    input[type="text"]:hover,
    input[type="tel"]:hover,
    input[type="url"]:hover,
    input[type="password"]:hover,
    textarea:hover,
    select:hover{font-size: inherit;}
}

Porém, ele tem alguns contras, notadamente um "salto" como resultado da rápida mudança no tamanho da fonte que ocorre entre os estados ed "focalizado" e "focalizado" - e o impacto do redesenho no desempenho

l3bel
fonte
Obrigado pelo seu feedback, @ MikeBoutin. Você pode compartilhar seu ambiente (dispositivo / versão iOS)?
L3bel 18/03/19
6

Inspirado na resposta de @jirikuchta, resolvi esse problema adicionando este pouco de CSS:

#myTextArea:active {
  font-size: 16px; /* `16px` is safer I assume, although `1rem` works too */
}

Sem JS, e não percebo nenhum flash ou qualquer coisa.

Vale ressaltar que a viewportcom maximum-scale=1também funciona, mas não quando a página é carregada como um iframe ou se você tiver algum outro script modificando o viewport, etc.

Meligy
fonte
4

Pseudo-elementos como :focusnão funcionam como costumavam. No iOS 11, é possível adicionar uma declaração de redefinição simples antes dos estilos principais (desde que você não os substitua por um tamanho de fonte menor).

/* Prevent zoom */
select, input, textarea {
  font-size: 16px;
}

Vale ressaltar que para bibliotecas CSS como o Tachyons.css, é fácil substituir acidentalmente o tamanho da fonte.

Por exemplo, class: f5é equivalente a:fontSize: 1rem que é bom se você mantiver a escala da fonte do corpo no padrão.

No entanto: se você escolher a classe de tamanho da fonte: f6isso será equivalente a fontSize: .875remuma pequena exibição para cima. Nesse caso, você precisará ser mais específico sobre suas declarações de redefinição:


  /* Prevent zoom */
  select, input, textarea {
    font-size: 16px!important;
  }

@media screen and (min-width: 30em) {

/* not small */

}
Scott Phillips
fonte
3

A propósito, se você usa o Bootstrap , pode apenas usar esta variante:

.form-control {
  font-size: 16px;
}
Bohdan Vorona
fonte
3

Eu tive que "corrigir" o problema de zoom automático nos controles de formulário de um site da Universidade Holandesa (que usava 15px nos controles de formulário). Eu vim com o seguinte conjunto de requisitos:

  • o usuário ainda deve poder aumentar o zoom
  • o tamanho da fonte deve permanecer o mesmo
  • sem flashes de estilos diferentes temporários
  • nenhum requisito jQuery
  • deve funcionar no iOS mais recente e não impedir qualquer outra combinação de SO / dispositivo
  • se possível, não há intervalos mágicos e, se necessário, limpe os temporizadores corretamente

Isto é o que eu vim até agora:

/*
NOTE: This code overrides the viewport settings, an improvement would be
      to take the original value and only add or change the user-scalable value
*/

// optionally only activate for iOS (done because I havn't tested the effect under other OS/devices combinations such as Android)
var iOS = navigator.platform && /iPad|iPhone|iPod/.test(navigator.platform)
if (iOS)
  preventZoomOnFocus();


function preventZoomOnFocus()
{
  document.documentElement.addEventListener("touchstart", onTouchStart);
  document.documentElement.addEventListener("focusin", onFocusIn);
}


let dont_disable_for = ["checkbox", "radio", "file", "button", "image", "submit", "reset", "hidden"];
//let disable_for = ["text", "search", "password", "email", "tel", "url", "number", "date", "datetime-local", "month", "year", "color"];


function onTouchStart(evt)
{
  let tn = evt.target.tagName;

  // No need to do anything if the initial target isn't a known element
  // which will cause a zoom upon receiving focus
  if (    tn != "SELECT"
      &&  tn != "TEXTAREA"
      && (tn != "INPUT" || dont_disable_for.indexOf(evt.target.getAttribute("type")) > -1)
     )
    return;

  // disable zoom
  setViewport("width=device-width, initial-scale=1.0, user-scalable=0");
}

// NOTE: for now assuming this focusIn is caused by user interaction
function onFocusIn(evt)
{
  // reenable zoom
  setViewport("width=device-width, initial-scale=1.0, user-scalable=1");
}

// add or update the <meta name="viewport"> element
function setViewport(newvalue)
{
  let vpnode = document.documentElement.querySelector('head meta[name="viewport"]');
  if (vpnode)
    vpnode.setAttribute("content",newvalue);
  else
  {
    vpnode = document.createElement("meta");
    vpnode.setAttribute("name", "viewport");
    vpnode.setAttribute("content", newvalue);
  }
}

Algumas notas:

  • Observe que, até agora, eu só o testei no iOS 11.3.1, mas o testarei em algumas outras versões em breve
  • O uso de focusIn events significa que ele requer pelo menos o iOS 5.1 (mas vejo sites que construímos trabalhando em versões iOS anteriores a 9 como um bônus legal de qualquer maneira)
  • Usando delegação de eventos porque muitos sites em que trabalho têm páginas que podem criar dinamicamente controles de formulário
  • Configurando eventListeners para o elemento html (documentElement) para não precisar aguardar a disponibilização do corpo (não se preocupe em verificar se o documento está pronto / carregado ou se é necessário aguardar o evento DOMContentLoaded)
Spellcoder
fonte
3

Em vez de simplesmente definir o tamanho da fonte como 16px, você pode:

  1. Estilize o campo de entrada para que seja maior que o tamanho pretendido, permitindo que o tamanho da fonte lógica seja definido como 16px.
  2. Use a scale()transformação CSS e as margens negativas para reduzir o campo de entrada até o tamanho correto.

Por exemplo, suponha que seu campo de entrada seja originalmente estilizado com:

input[type="text"] {
    border-radius: 5px;
    font-size: 12px;
    line-height: 20px;
    padding: 5px;
    width: 100%;
}

Se você aumentar o campo aumentando todas as dimensões em 16/12 = 133,33% e reduza usando scale()em 12/16 = 75%, o campo de entrada terá o tamanho visual correto (e tamanho da fonte) e não haverá zoom foco.

Como scale()afeta apenas o tamanho visual, você também precisará adicionar margens negativas para reduzir o tamanho lógico do campo.

Com este CSS:

input[type="text"] {
    /* enlarge by 16/12 = 133.33% */
    border-radius: 6.666666667px;
    font-size: 16px;
    line-height: 26.666666667px;
    padding: 6.666666667px;
    width: 133.333333333%;

    /* scale down by 12/16 = 75% */
    transform: scale(0.75);
    transform-origin: left top;

    /* remove extra white space */
    margin-bottom: -10px;
    margin-right: -33.333333333%;
}

o campo de entrada terá um tamanho de fonte lógica de 16px enquanto parece ter texto de 12px.

Tenho uma postagem no blog em que vou detalhar um pouco mais e tenho este exemplo como HTML visível:
Não há zoom de entrada no Safari no iPhone, a maneira perfeita de pixel

Jeffery To
fonte
3

Mesmo com essas respostas, levei três dias para descobrir o que estava acontecendo e talvez eu precise da solução novamente no futuro.

Minha situação era um pouco diferente da descrita.

No meu, eu tinha um texto editável em uma div na página. Quando o usuário clicou em uma div DIFERENTE, um botão das sortes, selecionei automaticamente algum texto na div editável por conteúdo (um intervalo de seleção que havia sido salvo e limpo anteriormente), executou um execCommand em rich text nessa seleção e o limpei novamente.

Isso me permitiu alterar invisivelmente as cores do texto com base nas interações do usuário com as divs de cores em outras partes da página, mantendo a seleção normalmente oculta para permitir que eles vejam as cores no contexto apropriado.

Bem, no Safari do iPad, clicar na div de cores resultou na ativação do teclado na tela, e nada que eu fiz impediu.

Finalmente descobri como o iPad está fazendo isso.

Ele escuta uma sequência de toque e toque que aciona uma seleção de texto editável.

Quando essa combinação acontece, ele mostra o teclado na tela.

Na verdade, ele faz um zoom de zorra onde expande a página subjacente enquanto amplia o texto editável. Levei um dia apenas para entender o que estava vendo.

Portanto, a solução que usei foi interceptar o touchstart e o touchend nesses divs de cores específicos. Nos dois manipuladores, paro a propagação e o borbulhamento e retorno falso. Mas, no evento touchend, desencadeio o mesmo comportamento que o clique disparou.

Antes, o Safari estava acionando o que eu acho que era "touchstart", "mousedown", "touchend", "mouseup", "mouseup", "click" e, por causa do meu código, uma seleção de texto, nessa ordem.

A nova sequência por causa das interceptações é simplesmente a seleção de texto. Todo o resto é interceptado antes que o Safari possa processá-lo e fazer suas coisas de teclado. As interceptações touchstart e touchend também impedem que os eventos do mouse sejam acionados e, no contexto, isso é totalmente correto.

Não conheço uma maneira mais fácil de descrever isso, mas acho que é importante tê-lo aqui, porque encontrei esse tópico dentro de uma hora depois de encontrar o problema.

Tenho 98% de certeza de que a mesma correção funcionará com caixas de entrada e qualquer outra coisa. Intercepte os eventos de toque e processe-os separadamente, sem permitir que eles se propaguem ou borbulhem e considere fazer qualquer seleção após um pequeno tempo limite, apenas para garantir que o Safari não reconheça a sequência como o acionador do teclado.

JBlitzen
fonte
Esta é uma ótima explicação do que o safari está fazendo. Obrigado!
Jeremy
2

Vejo pessoas aqui fazendo coisas estranhas com JavaScript ou a função de janela de exibição e desativando o zoom manual nos dispositivos. Isso não deve ser uma solução na minha opinião. A adição desse trecho de CSS desativará o zoom automático no iOS sem alterar o tamanho da fonte para um número fixo como 16px.

Por padrão, eu uso o tamanho da fonte de 93,8% (15px) nos campos de entrada e, adicionando meu snippet CSS, ele permanece em 93,8%. Não há necessidade de alterar para 16px ou torná-lo um número fixo.

input[type="text"]:focus,
textarea:focus {
    -webkit-text-size-adjust: 100%;
}
Jack Ottermans
fonte
5
Isso não funciona para mim, testado com o iOS 6 e o ​​iOS 9.2.1 mais recentes. Aqui está uma página reproduzível mínima: pastebin.com/bh5Zhe9h Ele ainda amplia o foco. Estranho que isso tenha sido publicado em 2015 e votado ainda não funciona no iOS 6. #
Alexandre Dieulot 15/02/16
2

Definir um tamanho de fonte (para campos de entrada) igual ao tamanho da fonte do corpo parece ser o que impede que o navegador diminua ou diminua o zoom. Sugiro que seja usada font-size: 1remcomo uma solução mais elegante.

sindiploma
fonte
1

Como o zoom automático (sem zoom) ainda é irritante no iPhone, aqui está um JavaScript baseado na sugestão da dlo de trabalhar com foco / desfoque.

O zoom é desativado assim que uma entrada de texto é ativada e reativada quando a entrada é deixada.

Nota: Alguns usuários podem não gostar de editar textos em uma pequena entrada de texto! Portanto, eu pessoalmente prefiro alterar o tamanho do texto da entrada durante a edição (consulte o código abaixo).

<script type="text/javascript">
<!--
function attachEvent(element, evtId, handler) {
    if (element.addEventListener) {
        element.addEventListener(evtId, handler, false);
    } else if (element.attachEvent) {
        var ieEvtId = "on"+evtId;
        element.attachEvent(ieEvtId, handler);
    } else {
        var legEvtId = "on"+evtId;
        element[legEvtId] = handler;
    }
}
function onBeforeZoom(evt) {
    var viewportmeta = document.querySelector('meta[name="viewport"]');
    if (viewportmeta) {
        viewportmeta.content = "user-scalable=0";
    }
}
function onAfterZoom(evt) {
    var viewportmeta = document.querySelector('meta[name="viewport"]');
    if (viewportmeta) {
        viewportmeta.content = "width=device-width, user-scalable=1";
    }
}
function disableZoom() {
    // Search all relevant input elements and attach zoom-events
    var inputs = document.getElementsByTagName("input");
    for (var i=0; i<inputs.length; i++) {
        attachEvent(inputs[i], "focus", onBeforeZoom);
        attachEvent(inputs[i], "blur", onAfterZoom);
    }
}
if (navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPad/i)) {
    attachEvent(window, "load", disableZoom);
}
// -->
</script>

O código a seguir alterará o tamanho do texto de uma entrada para 16 pixels (calculado, ou seja, no tamanho atual do zoom) durante o foco do elemento. O iPhone não aumentará automaticamente o zoom.

Nota: O fator de zoom é calculado com base na janela window.innerWidth e na tela do iPhone com 320 pixels. Isso será válido apenas para o iPhone no modo retrato.

<script type="text/javascript">
<!--
function attachEvent(element, evtId, handler) {
    if (element.addEventListener) {
        element.addEventListener(evtId, handler, false);
    } else if (element.attachEvent) {
        var ieEvtId = "on"+evtId;
        element.attachEvent(ieEvtId, handler);
    } else {
        var legEvtId = "on"+evtId;
        element[legEvtId] = handler;
    }
}
function getSender(evt, local) {
    if (!evt) {
        evt = window.event;
    }
    var sender;
    if (evt.srcElement) {
        sender = evt.srcElement;
    } else {
        sender = local;
    }
    return sender;
}
function onBeforeZoom(evt) {
    var zoom = 320 / window.innerWidth;
    var element = getSender(evt);
    element.style.fontSize = Math.ceil(16 / zoom) + "px";
}
function onAfterZoom(evt) {
    var element = getSender(evt);
    element.style.fontSize = "";
}
function disableZoom() {
    // Search all relevant input elements and attach zoom-events
    var inputs = document.getElementsByTagName("input");
    for (var i=0; i<inputs.length; i++) {
        attachEvent(inputs[i], "focus", onBeforeZoom);
        attachEvent(inputs[i], "blur", onAfterZoom);
    }
}
if (navigator.userAgent.match(/iPhone/i)) {
    attachEvent(window, "load", disableZoom);
}
// -->
</script>
BurninLeo
fonte
1

Levei um tempo para encontrá-lo, mas aqui está o melhor código que eu encontrei ...... http://nerd.vasilis.nl/prevent-ios-from-zooming-onfocus/

var $viewportMeta = $('meta[name="viewport"]');
$('input, select, textarea').bind('focus blur', function(event) {
$viewportMeta.attr('content', 'width=device-width,initial-scale=1,maximum-scale=' +        (event.type == 'blur' ? 10 : 1));
});
Stephen Walsh
fonte
1

Com base na resposta de Stephen Walsh ... Esse código funciona sem alterar o tamanho da fonte das entradas em foco (o que parece ruim), e ainda funciona com o FastClick , que eu sugiro que seja adicionado a todos os sites móveis para ajudar a trazer o "snappy". Ajuste sua "largura da janela de exibição" para atender às suas necessidades.

// disable autozoom when input is focused
    var $viewportMeta = $('head > meta[name="viewport"]');
    $('input, select, textarea').bind('touchend', function(event) {
        $viewportMeta.attr('content', 'width=640, user-scalable=0');
        setTimeout(function(){ $viewportMeta.attr('content', 'width=640, user-scalable=1'); }, 1)
    });
rochoso
fonte
Se o usuário já tivesse aumentado um pouco o zoom antes de clicar no controle de entrada, essa solução faria com que a janela de exibição "subisse" de repente?
Bruno Torquato
Sim, parece, mas não parece mais perturbador do que o efeito anterior de "zoom" que acontecia toda vez que o usuário clica em uma entrada.
Pete
1

Um comentário para a resposta principal sobre como definir o tamanho da fonte para 16px perguntou como essa é uma solução, e se você quiser uma fonte maior / menor.

Eu não sei sobre todos vocês, mas usar px para tamanhos de fonte não é o melhor caminho a seguir, você deve usá-los.

Encontrei esse problema no meu site responsivo, onde meu campo de texto é maior que 16 pixels. Eu tinha meu contêiner de formulário definido como 2rem e meu campo de entrada definido como 1.4em. Nas minhas consultas para dispositivos móveis, altero o tamanho da fonte html, dependendo da janela de visualização. Como o html padrão é 10, meu campo de entrada calcula para 28 px na área de trabalho

Para remover o zoom automático, tive que alterar minha entrada para 1.6em. Isso aumentou o tamanho da minha fonte para 32px. Apenas um pouco mais alto e quase imperceptível. No iPhone 4 e 5, altero o tamanho da fonte html para 15px para retrato e de volta para 10px para paisagem. Parecia que o ponto ideal para esse tamanho de pixel era 48px, motivo pelo qual mudei de 1,4em (42px) para 1,6em (48px).

O que você precisa fazer é encontrar o ponto ideal no tamanho da fonte e depois convertê-lo para trás nos tamanhos rem / em.

Jon Tinsman
fonte
1

Aqui está um truque que usei em um dos meus projetos:

select {
    font-size: 2.6rem; // 1rem = 10px
    ...
    transform-origin: ... ...;
    transform: scale(0.5) ...;
}

Acabei com os estilos e a escala iniciais que eu queria, mas sem zoom no foco.

magom001
fonte