Отключить функцию автоматического увеличения ввода «Текст» - Safari на iPhone

541

Я сделал HTML-страницу с <input>тегом type="text". Когда я нажимаю на него с помощью Safari на iPhone, страница становится больше (автоматическое увеличение). Кто-нибудь знает, как это отключить?

Эдуардо Черногория
источник
8
Для всех пользователей Twitter Bootstrap, приземляющихся здесь: см. Также этот выпуск Github .
Йерун
7
Я думаю, что @daxmacrog answer точно отвечает тому, что вы хотите, готовы ли вы принять это, чтобы оно могло подняться на вершину и сэкономить много переделок от людей, которые все это читают? 2018 Ответ: stackoverflow.com/a/46254706/172651
Эволюция
@ Получите ответ, который вы говорили о перерывах в функциях Android: увеличение и уменьшение. daxmacrog ответ ошибочен.
MH
5
Клянусь, Apple создает эти антифункции, чтобы просто поиграть с нашими головами.
Эндрю Костер
@AndrewKoster, я согласен с вами даже сейчас, в 2020 году.
Ашок

Ответы:

492

Браузер будет изменять масштаб, если размер шрифта меньше, чем 16pxразмер шрифта по умолчанию для элементов формы 11px(по крайней мере, в Chrome и Safari).

Кроме того, selectэлемент должен иметь присоединенный focusпсевдокласс.

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

Не обязательно использовать все выше, вы можете просто стиль элементы вам нужно, например: просто text, numberи textarea:

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

Альтернативное решение, чтобы входные элементы наследовали от родительского стиля:

body {
  font-size: 16px;
}
input[type="text"] {
  font-size: inherit;
}
Srikanth
источник
81
Просто чтобы покрыть все: 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; }
Ник Барбье
8
@Nic Вы должны использовать select:focus. У меня была такая же проблема.
DGibbs
141
Я не понимаю, как это исправить? Что делать, если я хочу уменьшить размер шрифта?
Брайан
47
правильно изменить метатег на: <meta name = "viewport" content = "width = device-width, initial-scale = 1, максимальный масштаб = 1, масштабируемый пользователем = 0" />
Milos Matic
37
@MilosMatic В большинстве случаев, вероятно, не очень хорошее решение, так как оно полностью предотвращает масштабирование страницы пользователем. Потенциально еще больше раздражает ваших посетителей.
BadHorsie
364

Вы можете запретить Safari автоматически увеличивать текстовые поля во время ввода данных пользователем, не отключая возможности пользователя увеличивать масштаб. Просто добавьте, maximum-scale=1но не указывайте атрибут пользовательского масштаба, предложенный в других ответах.

Это полезный вариант, если у вас есть форма в слое, которая «плавает» при увеличении, что может привести к тому, что важные элементы пользовательского интерфейса переместятся за пределы экрана.

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

daxmacrog
источник
66
Это решение 2018+. Подними это, как будто от этого зависит твоя жизнь.
Хенрик Петтерсон
17
Это сломает возможность масштабирования устройств Android
fen1ksss
4
@daxmacrog, вы правы, но ОП не упомянул, хочет ли он сломать андроидов, допустив необходимое поведение. Это где лично я взял неправильный вариант. Конечно, лучше уточнить.
fen1ksss
13
@HenrikPetterson Это делает больше, чем просто отключение автоматического масштабирования, как указано в OP, а также отключает масштабирование пинч. Так что я не думаю, что это решение 2018+.
Андре Верланг
4
@ АндреВерланг Это не точно. Как ясно указано в ответе, это решение не отключает масштабирование в Safari (или Firefox), о чем спрашивал ОП. Но, как указывалось в предыдущих комментариях, он отключает пользовательское масштабирование на устройствах Android и в Chrome на iOS.
Даксмакрог
223
@media screen and (-webkit-min-device-pixel-ratio:0) { 
  select:focus,
  textarea:focus,
  input:focus {
    font-size: 16px;
    background: #eee;
  }
}

Новое: IOS все равно будет масштабироваться, если вы не используете 16px на входе без фокуса.

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

Я добавил фон, так как IOS не добавляет фон на выбор.

Кристина
источник
9
Это работает не только для сафари на iOS (iphone / ipad / ipod), но также для Safari / OSX и Chrome (windows и Mac). Так что, если вы пытаетесь нацелиться на iphone, это не сработает.
Redtopia
31
Почему все говорят 16px, но никто не хочет упоминать, почему именно 16px? Почему такое произвольное число? Почему мы должны установить размер текста поля формы в 16px, а не .. скажем, 1.8rem или 2.5em или около того? Это просто глупая ошибка проприетарной ОС?
Биби
14
@Beebee Размер шрифта 100% составляет 16px, что по умолчанию для большинства, если не для всех браузеров (для настольных компьютеров тоже). IOS использует его по умолчанию, вероятно, потому что это удобный размер для чтения. Почему это так, я не потрудился посмотреть, мне все равно.
Кристина
5
Используйте @media screen and (-webkit-min-device-pixel-ratio:0) and (max-device-width:1024px)для ограничения эффекта на iPhone, но не изменяйте веб-сайты при просмотре в Chrome.
BurninLeo
9
Вместо использования медиа-запроса, вы должны использовать @supports (-webkit-overflow-scrolling: touch), так как эта функция CSS существует только на iOS
Джеймс Моран
189

Если ваш сайт предназначен для мобильных устройств, вы можете решить не разрешать масштабирование.

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

Это решает проблему, с которой ваша мобильная страница или форма будут «плавать» вокруг.

Марчеллино Боммезийн
источник
123
Технически правильно, но я не согласен с аргументацией. Отключение масштабирования пользователя на правильно оформленном сайте, как правило, все еще плохая идея.
Fer
20
«Правильно спроектированный» очень субъективен. Рассмотрим фиксированный заголовок размером 50px в верхней части сайта, который полностью адаптивен и должен работать во всех браузерах. Масштабирование в iOS Safari нарушает позиционирование заголовка и в значительной степени разрушает весь сайт.
Redtopia
62
Отключение функции масштабирования пользователя - ужасная практика с точки зрения UX, и ее действительно следует избегать любой ценой. Возможность свободного увеличения является основной функцией доступности и элементом управления, который вы никогда не должны забирать у пользователя.
Габриэль Лютье
72
В нативных мобильных приложениях вы никогда не получите возможность масштабирования, и они прекрасно работают, почему веб-приложение будет другим? Если вы установите соответствующий размер шрифта и высоту строки с четкими контрастами, все будет в порядке.
Jotav
39
Те, кто использует аргумент «все хорошо в нативных приложениях», упускают из виду тот факт, что хорошо сделанные нативные приложения придерживаются таких настроек доступа на уровне ОС, как размер текста. Пожилые и зрячие пользователи могут использовать шрифты очень большого размера для всей ОС, поскольку им это необходимо . Веб-приложения часто не поддерживают или не могут придерживаться этого параметра, поэтому жизненно важно разрешить встроенную в веб-браузер функциональность доступности, такую ​​как масштабирование. Поверьте мне, что бы вы ни считали идеально читабельным, есть люди, которые не находят это достаточно ясным. Вы не принимать этот параметр от пользователей , если вы цените удобство и простоту использования.
Райан Уильямс
72

В итоге ответ таков: установите размер шрифта элементов формы не менее 16 пикселей

Nik
источник
Да, это определенно лучший способ избежать масштабирования на мобильных устройствах. Нет JS, нет взломов, нет обходных путей вообще. Но даже с 16px я заметил очень небольшое увеличение моих страниц, поэтому я попробовал 17px, 18px ... чтобы посмотреть, что произойдет.
ed1nh0
8
Рекомендуется объявлять 100% для тела, кнопки, ввода, текстовой области и выбранных элементов. Это позволяет пользователю установить значение по умолчанию, отличное от 16px, поставляемого с браузерами. Кто-то, у кого проблемы с чтением на экране, может установить значение по умолчанию 18px или 20px. Вы не хотите отменять их выбор, навязывая им 16px. Однако, когда дело доходит до iOS, они решили увеличить любое значение, которое, по словам их HIG, слишком мало. К сожалению, похоже, что он не интерпретирует значение 100%, поэтому мы застряли, добавляя значение по умолчанию, чтобы его утешить.
J. Hogue
RE iOS Safari, по состоянию на этот комментарий кажется, что Safari правильно интерпретирует font-size: 100%значение и получает необходимые 16px.
Натан Лафферти
36
input[type='text'],textarea {font-size:1em;}
stormsweeper
источник
3
Обратите внимание, что установка пользовательского масштабирования на no отключит все масштабирование, что, вероятно, является плохой идеей.
штормовщик
18
Это работает только в том случае, если размер основного шрифта по умолчанию (не указан, или 1em, или 100%). Если вы установили нестандартный размер шрифта, вы можете установить font-sizeв своем фрагменте, 16pxчтобы избежать автоматического масштабирования.
Алан Х.
Я знаю, что этот вопрос был направлен на iPhone, но он более совместим между платформами и в будущем для большего количества платформ / устройств, я попробовал подход 16px, но на планшете Android только уменьшил эффект автоматического масштабирования. Установка на «1em», как указано в посте, решила проблему.
toddles_fp
3
Ни то, 1emни другое не 1remявляется правильным решением, потому что оба могут быть меньше, 16pxа Safari требует, по крайней мере, 16pxне увеличивать масштаб.
Finesse
2
Я использовал решение Viewport, но оно не сработало, 16px решение работает нормально, но 16px слишком велико для ввода моего сайта, есть ли какое-нибудь 3-е решение
Suneth Kalhara
21

Правильный способ исправить эту проблему - изменить окно просмотра мета на:

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

Милош Матич
источник
32
Это не обязательно «правильный» способ предотвратить такое поведение. Mobile Safari увеличивает масштаб, если текст считается слишком маленьким для чтения. Отключение масштабирования все вместе является сложным делом и лишает пользователей возможности взаимодействовать с вашей страницей так, как они могут ожидать.
AlecRust
3
Очевидно, в iOS10 Apple изменила свойство максимального масштаба, чтобы оно больше не учитывалось, позволяя всем сайтам увеличивать масштаб независимо от его настройки.
Вольфр
3
Это работает для версии iOS10 20 / сентябрь / 2016 ... по крайней мере, работает на моем приложении ... Спасибо !!! Прежде чем использовать <meta name = "viewport" content = "width = device-width, initial-scale = 1, минимальный масштаб = 1 , максимальный масштаб = 1"> Но я переключил его на строку в ответе и это сработало ...
eljamz
1
«Убедитесь, что масштабирование в браузере не блокируется метаэлем области просмотра страницы, чтобы его можно было использовать для увеличения страницы до 200%. Следует избегать ограничительных значений для масштабируемых пользователем и максимально масштабных атрибутов этого метаэлемента». w3.org/TR/mobile-accessibility-mapping/#zoom-magnification
danielnixon
Я видел комментарии о том, что некоторые из этих мета-тегов не работают на iOS 10, и я знаю, что вышеописанное работает на Chrome для iOS, по крайней мере. :) Спасибо!
cbloss793
16

Там нет чистого способа я мог бы найти, но вот взломать ...

1) Я заметил, что событие наведения мыши происходит до масштабирования, но масштабирование происходит до событий mousedown или focus.

2) Вы можете динамически изменять тег окна просмотра META, используя javascript (см. Включить / отключить увеличение iPhone Safari с помощью Javascript? )

Итак, попробуйте это (показано в jquery для компактности):

$("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" />');
}

Это определенно хак ... могут быть ситуации, когда при наведении / выключении мыши не всегда перехватываются входы / выходы, но это хорошо сработало в моих тестах и ​​является хорошим началом.

ДЛО
источник
5
Не уверен, когда поведение Safari могло измениться, но теперь (iOS6.0.1) mousedown происходит до автоматического увеличения. Таким образом, в моем предыдущем решении масштабирование снова включается слишком рано. Я не придумал адекватного решения, так как все события, которые я попробовал, теперь происходят до увеличения. Вы можете снова включить масштабирование при нажатии клавиши или размытие, но есть некоторые сценарии, которые могут пропустить (например, если пользователь хочет вручную увеличить масштаб, прежде чем начать что-либо печатать).
ДЛО
15

Добавьте пользовательский масштабируемый = 0 к мета области просмотра следующим образом

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

Работал для меня :)

Туйен Цао
источник
11
«Убедитесь, что масштабирование в браузере не блокируется метаэлем области просмотра страницы, чтобы его можно было использовать для увеличения страницы до 200%. Следует избегать ограничительных значений для масштабируемых пользователем и максимально масштабных атрибутов этого метаэлемента». w3.org/TR/mobile-accessibility-mapping/#zoom-magnification
danielnixon
9
Это нарушает правила доступности, определенные W3.
Джошуа Рассел
работал для меня, также это лучшее решение для меня, так как я хочу свободу изменять размеры входного шрифта ниже 16px и не хочу взломать JS
Blue Bot
14

Мне недавно (сегодня: D) пришлось интегрировать это поведение. Чтобы не влиять на исходные поля дизайна, включая поля со списком, я решил применить преобразование в фокусе поля:

input[type="text"]:focus, input[type="password"]:focus,
textarea:focus, select:focus {
  font-size: 16px;
}
piouPiouM
источник
К вашему сведению, это хорошо работало на моем iphone 5 с iOS 6, но на iphone 4 с iOS 5 в портретном режиме стиль фокусировки был применен после увеличения. Может быть, что-то неуловимое происходит, я не стал расследовать дальше.
Виш
Я просто хочу сказать, что у меня много разных запросов, использующих масштабирование для ускорения разработки, и в зависимости от того, насколько вы увеличите масштаб, будет определено, какой размер шрифта вам нужен
Майк
: focus у меня не работал iOS 10.2 iPhone 6, но ввод [type = "text"]: hover работал хорошо.
Amirhossein Rzd
13

Как уже указывалось во многих других ответах, этого можно достичь, добавив maximum-scaleметатег viewport. Однако это отрицательно сказывается на отключении пользовательского масштабирования на устройствах Android . ( Он не отключает масштабирование пользователя на устройствах iOS начиная с версии 10 ).

Мы можем использовать JavaScript для динамического добавления maximum-scaleв мету, viewportкогда устройством является iOS. Это обеспечивает лучшее из обоих миров: мы позволяем пользователю увеличивать масштаб и не позволяем iOS масштабировать текстовые поля в фокусе.

| 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               |

Код:

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();
}
Оливер Джозеф Эш
источник
почему вы создаете копию addMaximumScaleToMetaViewport? Это исключительно по семантическим причинам?
Pherrymason
Да, просто сопоставление функции с другим именем, чтобы было понятно, как она используется.
Оливер Джозеф Эш
8

Взлом Javascript, который работает на iOS 7. Это основано на ответе @dlo, но события mouseover и mouseout заменяются событиями touchstart и touchend. По сути, этот сценарий добавляет тайм-аут на полсекунды, прежде чем зум снова включится, чтобы предотвратить увеличение.

$("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" />');
} 
Илкка Р.
источник
Это сработало лучше для меня. Но я изменил события touchstart / touchend на одно событие 'focus' с помощью zoomDisable и zoomEnable.
Джастин Клауд
Добавление задержки, кажется, работает довольно хорошо на более новых версиях iOS, но интересно, что она не очень хорошо работает, когда установлено 250 мс. Это намекает на то, что при некоторых обстоятельствах 500 мсек тоже могут не работать, но если это работает большую часть времени, я думаю, это лучше, чем вообще не работать. Хорошая мысль.
ДЛО
7

Это сработало для меня:

input, textarea {
    font-size: initial;
}

источник
Красиво просто, но есть ли способ контролировать, что это за «начальный» размер?
2540625 15.09.14
Я не проверял это, но это должен быть способ контролировать размер шрифта. (пожалуйста, дайте мне знать, если это работает, и я обновлю свой ответ) body {font-size: 20px; } вход {размер шрифта: наследовать; }
7

Я использовал решение Кристины выше, но с небольшой модификацией для начальной загрузки и другим правилом, применимым к настольным компьютерам. Размер шрифта по умолчанию в Bootstrap составляет 14 пикселей, что вызывает увеличение. Следующее изменяет его на 16px для «элементов управления форм» в Bootstrap, предотвращая масштабирование.

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

И вернемся к 14px для не мобильных браузеров.

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

Я попытался использовать .form-control: focus, который оставил его на 14px, кроме фокуса, который изменил его на 16px, и это не решило проблему масштабирования с iOS8. По крайней мере, на моем iPhone, использующем iOS8, размер шрифта должен быть 16px перед фокусировкой, чтобы iPhone не масштабировал страницу.

Тэнни О'Хейли
источник
6

Я сделал это, также с 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'));
});

Конечно, некоторые другие элементы интерфейса, возможно, придется адаптировать, если этот 16pxразмер шрифта нарушает дизайн.

Николас Хойзи
источник
4
Это стильно Это стильно. Я из каламбура. Умный подход.
Crowjonah
@ Wolff вы пробовали на реальном устройстве?
Николас Хойзи
1
Это сработало для нас на iOS 12. Мне больше нравится этот подход, а не копаться с преобразованиями CSS и отрицательными полями.
анонимно -
6

Через некоторое время попыток я придумал это решение

// 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 = "";
});

На «mousedown» он устанавливает размер шрифта ввода в 16px. Это предотвратит увеличение. На событии фокуса он изменяет размер шрифта обратно к начальному значению.

В отличие от ранее опубликованных решений, это позволит вам установить любой размер шрифта для ввода.

jirikuchta
источник
Это на самом деле работает для меня, тем более, что в новых версиях iOS вы не можете использовать метатег viewport для отключения масштабирования.
mparizeau
Подтверждено , работающих на IOS 12.1, спасибо
Ziki
6

Прочитав здесь почти каждую строчку и протестировав различные решения, это благодаря всем, кто поделился своими решениями, что я придумал, протестировал и работал для меня на 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;}
}

Тем не менее, он имеет некоторые недостатки: заметно «скачок» в результате быстрого изменения размера шрифта, происходящего между состояниями «зависание» и «фокус», а также влияние перерисовки на производительность.

l3bel
источник
Спасибо за ваш отзыв, @MikeBoutin. Можете ли вы поделиться своим env (версия для устройства / iOS)?
13
6

Вдохновленный ответом @jirikuchta, я решил эту проблему, добавив немного CSS:

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

Нет JS, и я не замечаю ни вспышки, ни чего-либо.

Стоит отметить, что viewportwith maximum-scale=1также работает, но не тогда, когда страница загружается как iframe, или если у вас есть другой скрипт, модифицирующий и viewportт. Д.

Meligy
источник
4

Псевдоэлементы вроде :focusне работают, как раньше. Начиная с iOS 11, простое объявление сброса может быть добавлено перед вашими основными стилями (при условии, что вы не переопределите их с меньшим размером шрифта).

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

Стоит отметить, что для библиотек CSS, таких как Tachyons.css, легко случайно изменить размер шрифта.

Например, class: f5эквивалентно:, fontSize: 1remчто хорошо, если вы сохранили масштаб шрифта основного текста по умолчанию.

Однако: если вы выберете класс размера шрифта: f6это будет эквивалентно fontSize: .875remнебольшому дисплею вверх. В этом случае вам нужно быть более точным в отношении объявлений сброса:


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

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

/* not small */

}
Скотт Филлипс
источник
3

Кстати, если вы используете Bootstrap , вы можете просто использовать этот вариант:

.form-control {
  font-size: 16px;
}
Богдан Ворона
источник
3

Мне пришлось «исправить» проблему с автоматическим увеличением в элементах управления формы для веб-сайта Голландского университета (который использовал 15px в элементах управления формой). Я выдвинул следующий набор требований:

  • пользователь все еще должен иметь возможность увеличить
  • размер шрифта должен оставаться прежним
  • нет вспышек временного другого стиля
  • не требуется JQuery
  • должен работать на новейшей iOS и не мешать любой другой комбинации ОС / устройства
  • по возможности нет магических таймаутов, а при необходимости правильно сбрасывайте таймеры

Это то, что я придумал до сих пор:

/*
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);
  }
}

Некоторые заметки:

  • Обратите внимание, что до сих пор я тестировал его только на iOS 11.3.1, но скоро опробую его на нескольких других версиях.
  • Использование событий focusIn означает, что для него требуется как минимум iOS 5.1 (но я считаю, что сайты, которые мы создаем, работающие в версиях для iOS старше 9, как крутой бонус)
  • Использование делегирования событий, потому что на многих сайтах, над которыми я работаю, есть страницы, которые могут динамически создавать элементы управления формой.
  • Установка для eventListeners элемента html (documentElement), чтобы не нужно было ждать, пока тело станет доступным (не нужно беспокоиться о проверке, находится ли документ в состоянии готовности / загрузки, или о необходимости ждать события DOMContentLoaded)
Spellcoder
источник
3

Вместо того, чтобы просто установить размер шрифта в 16px, вы можете:

  1. Стиль поля ввода так, чтобы он был больше, чем предполагалось, позволяя установить логический размер шрифта 16 пикселей.
  2. Используйте scale()CSS-преобразование и отрицательные поля, чтобы уменьшить поле ввода до правильного размера.

Например, предположим, что ваше поле ввода изначально оформлено с помощью:

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

Если вы увеличите поле, увеличив все размеры на 16/12 = 133,33%, а затем уменьшите scale()на 12/16 = 75%, поле ввода будет иметь правильный визуальный размер (и размер шрифта), и масштабирование будет отсутствовать. фокус.

Поскольку это scale()влияет только на визуальный размер, вам также необходимо добавить отрицательные поля, чтобы уменьшить логический размер поля.

С этим 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%;
}

поле ввода будет иметь логический размер шрифта 16 пикселей, в то время как будет отображаться текст размером 12 пикселей.

У меня есть запись в блоге, в которой я немного подробнее расскажу, и этот пример представлен в виде просматриваемого HTML:
в iPhone Safari нет увеличения при вводе, идеальный пиксельный способ

Джеффри То
источник
3

Даже с этими ответами мне потребовалось три дня, чтобы понять, что происходит, и мне может понадобиться решение снова в будущем.

Моя ситуация немного отличалась от описанной.

У меня был какой-то спорный текст в div на странице. Когда пользователь нажал на кнопку DIFFERENT div, своего рода кнопку, я автоматически выделил некоторый текст в contenteditable div (диапазон выбора, который ранее был сохранен и очищен), запустил execCommand расширенного текста в этом выделении и очистил его снова.

Это позволило мне незаметно изменять цвета текста на основе взаимодействия пользователя с цветовыми элементами в других местах на странице, сохраняя при этом выделение, как правило, скрытым, чтобы они могли видеть цвета в правильном контексте.

Что ж, на iPad Safari нажатие на div цвета привело к появлению экранной клавиатуры, и я ничего не сделал, чтобы помешать этому.

Я наконец понял, как iPad делает это.

Он прослушивает последовательность прикосновений и касаний, которые запускают выделение редактируемого текста.

Когда эта комбинация происходит, она показывает экранную клавиатуру.

На самом деле, он выполняет масштабирование тележки, где он расширяет нижележащую страницу, в то же время увеличивая редактируемый текст. Мне потребовался день, чтобы понять, что я вижу.

Таким образом, решение, которое я использовал, состояло в том, чтобы перехватить как touchstart, так и touchend для этих конкретных цветовых элементов. В обоих обработчиках я прекращаю распространение и всплывающие сообщения и возвращаю false. Но в событии touchend я запускаю то же поведение, что и нажатие.

Итак, раньше Safari запускал, как мне кажется, «touchstart», «mousedown», «touchend», «mouseup», «click», и из-за моего кода, выделение текста, в таком порядке.

Новая последовательность из-за перехватов - это просто выделение текста. Все остальное перехватывается до того, как Safari сможет обработать его и выполнить работу с клавиатурой. Перехваты touchstart и touchend также предотвращают запуск событий мыши, и в контексте это вполне нормально.

Я не знаю более простой способ описать это, но я думаю, что важно иметь его здесь, потому что я нашел эту тему в течение часа после первого столкновения с проблемой.

Я на 98% уверен, что то же самое исправление будет работать с полями ввода и всем остальным. Перехватывайте события касания и обрабатывайте их отдельно, не позволяя им распространяться или пузыриться, и подумайте о том, чтобы сделать какие-либо выборки после небольшого тайм-аута, просто чтобы убедиться, что Safari не распознает последовательность как триггер клавиатуры.

JBlitzen
источник
Это отличное объяснение того, что делает сафари. Спасибо!
Джереми
2

Я вижу, что люди здесь делают странные вещи с помощью JavaScript или функции окна просмотра и отключают все масштабирование вручную на устройствах. Это не должно быть решением по моему мнению. Добавление этого фрагмента CSS отключит автоматическое масштабирование в iOS без изменения размера шрифта до фиксированного числа, например 16px.

По умолчанию я использую размер шрифта 93,8% (15 пикселей) в полях ввода и добавляя свой фрагмент кода CSS, он остается на уровне 93,8%. Не нужно менять на 16px или сделать его фиксированным числом.

input[type="text"]:focus,
textarea:focus {
    -webkit-text-size-adjust: 100%;
}
Джек Оттерманс
источник
5
Это не работает для меня, протестировано как с последней iOS 6, так и с iOS 9.2.1. Вот минимальная воспроизводимая страница: pastebin.com/bh5Zhe9h Она по-прежнему увеличивает фокус. Странно, что это было опубликовано в 2015 году и проголосовало еще, но не работает в iOS 6.
Александр Dieulot
2

Установка размера шрифта (для полей ввода), равного размеру шрифта тела, кажется, что мешает браузеру уменьшать или уменьшать масштаб. Я бы предложил использовать font-size: 1rem как более элегантное решение.

sindiploma
источник
1

Поскольку автоматическое увеличение (без уменьшения) все еще раздражает iPhone, вот JavaScript, основанный на предложении dlo работать с фокусом / размытием.

Масштабирование отключается, как только ввод текста дублируется и повторно активируется, когда ввод оставлен.

Примечание: некоторые пользователи могут не ценить редактирование текстов при небольшом вводе текста! Поэтому я лично предпочитаю изменять размер текста ввода во время редактирования (см. Код ниже).

<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>

Следующий код изменит размер текста ввода до 16 пикселей (рассчитывается, т. Е. В текущем размере масштабирования), когда элемент находится в фокусе. Поэтому iPhone не будет автоматически увеличивать масштаб.

Примечание. Коэффициент масштабирования рассчитывается на основе window.innerWidth и дисплея iPhone с разрешением 320 пикселей. Это будет действительно только для iPhone в портретном режиме.

<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
источник
1

Мне потребовалось некоторое время, чтобы найти его, но вот лучший код, который я нашел ...... 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));
});
Стивен Уолш
источник
1

Основываясь на ответе Стивена Уолша ... Этот код работает без изменения размера шрифта для ввода в фокусе (что выглядит неубедительно), плюс он все еще работает с FastClick , который я предлагаю добавить ко всем мобильным сайтам, чтобы помочь придать "мгновенный" эффект. Отрегулируйте «ширину области просмотра» в соответствии с вашими потребностями.

// 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)
    });
скалистый
источник
Если пользователь уже немного увеличил масштаб перед тем, как щелкнуть элемент управления вводом, приведет ли это решение к тому, что область просмотра внезапно "масштабируется"?
Бруно Торквато
Да, это так, но это не выглядит более резким, чем предыдущий эффект «увеличения», который происходил каждый раз, когда пользователь нажимал на вход.
Пит
1

В комментарии к главному ответу об установке размера шрифта в 16px спрашивалось, как это решение, что делать, если вы хотите увеличить / уменьшить шрифт.

Я не знаю всех вас, но использование px для размеров шрифта не лучший способ, вы должны использовать em.

Я столкнулся с этой проблемой на моем адаптивном сайте, где мое текстовое поле больше 16 пикселей. У меня был контейнер формы для 2rem и поле ввода 1.4em. В моих мобильных запросах я изменяю размер шрифта html в зависимости от области просмотра. Поскольку html по умолчанию равен 10, мое поле ввода рассчитывается на 28 пикселей на рабочем столе

Чтобы удалить авто-зум, мне пришлось изменить свой ввод на 1.6em. Это увеличило мой размер шрифта до 32 пикселей. Просто чуть выше и едва заметно. На моем iPhone 4 & 5 я изменяю свой размер шрифта html на 15 пикселей для портрета и обратно на 10 пикселей для ландшафта. Похоже, что лучшим местом для этого размера пикселя было 48 пикселей, поэтому я перешел с 1.4em (42px) на 1.6em (48px).

Все, что вам нужно сделать, это найти нужное место на шрифте, а затем преобразовать его обратно в ваши размеры rem / em.

Джон Тинсман
источник
1

Вот взлом, который я использовал на одном из моих проектов:

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

Закончил начальные стили и масштаб, который я хотел, но без фокусировки.

magom001
источник