Disable Auto Zoom in Input “Text” tag - Safari on iPhone

一世执手 提交于 2019-12-17 02:03:10

问题


I made an HTML page that has an <input> tag with type="text". When I click on it using Safari on iPhone, the page becomes larger (auto zoom). Does anybody know how to disable this?


回答1:


The browser will zoom if the font-size is less than 16px and the default font-size for form elements is 11px (at least in Chrome and Safari).

Additionally, the select element needs to have the focus pseudo-class attached.

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

It's not necessary to use all the above, you can just style the elements you need, eg: just text, number, and textarea:

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

Alternate solution to have the input elements inherit from a parent style:

body {
  font-size: 16px;
}
input[type="text"] {
  font-size: inherit;
}



回答2:


You can prevent Safari from automatically zooming in on text fields during user input without disabling the user’s ability to pinch zoom. Just add maximum-scale=1 but leave out the user-scale attribute suggested in other answers.

It is a worthwhile option if you have a form in a layer that “floats” around if zoomed, which can cause important UI elements to move off screen.

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




回答3:


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

New: IOS will still zoom, unless you use 16px on the input without the focus.

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

I added a background since IOS adds no background on the select.




回答4:


If your website is properly designed for a mobile device you could decide not allow scaling.

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

This solves the problem that your mobile page or form is going to 'float' around.




回答5:


In summary the answer is: set the font size of the form elements to at least 16px




回答6:


input[type='text'],textarea {font-size:1em;}



回答7:


Proper way to fix this issue is to change meta viewport to:

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



回答8:


There's no clean way I could find, but here's a hack...

1) I noticed that the mouseover event happens prior to the zoom, but the zoom happens before mousedown or focus events.

2) You can dynamically change the META viewport tag using javascript (see Enable/disable zoom on iPhone safari with Javascript?)

So, try this (shown in jquery for compactness):

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

This is definitely a hack... there may be situations where mouseover/down don't always catch entries/exits, but it worked well in my tests and is a solid start.




回答9:


I recently (today :D) had to integrate this behavior. In order to not impact the original design fields, including combo, I opted to apply the transformation at the focus of the field:

input[type="text"]:focus, input[type="password"]:focus,
textarea:focus, select:focus {
  font-size: 16px;
}



回答10:


Add user-scalable=0 to viewport meta as following

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

Worked for me :)




回答11:


Javascript hack which is working on iOS 7. This is based on @dlo 's answer but mouseover and mouseout events are replaced by touchstart and touchend events. Basicly this script add a half second timeout before the zoom would enabled again to prevent zooming.

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



回答12:


This worked for me:

input, textarea {
    font-size: initial;
}



回答13:


I used Christina's solution above, but with a small modification for bootstrap and another rule to apply to desktop computers. Bootstrap's default font-size is 14px which causes the zoom. The following changes it to 16px for "form controls" in Bootstrap, preventing the zoom.

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

And back to 14px for non-mobile browsers.

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

I tried using .form-control:focus, which left it at 14px except on focus which changed it to 16px and it did not fix the zoom problem with iOS8. At least on my iPhone using iOS8, the font-size has to be 16px before focus for the iPhone to not zoom the page.




回答14:


I did this, also with 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'));
});

Of course, some other elements in the interface may have to be adapted if this 16px font-size breaks the design.




回答15:


After a while of while trying I came up with this solution

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

On "mousedown" it sets font-size of input to 16px. This will prevent the zooming. On focus event it changes font-size back to initial value.

Unlike solutions posted before, this will let you set the font-size of the input to whatever you want.




回答16:


As many other answers have already pointed out, this can be achieved by adding maximum-scale to the meta viewport tag. However, this has the negative consequence of disabling user zoom on Android devices. (It does not disable user zoom on iOS devices since v10.)

We can use JavaScript to dynamically add maximum-scale to the meta viewport when the device is iOS. This achieves the best of both worlds: we allow the user to zoom and prevent iOS from zooming into text fields on focus.

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

Code:

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;

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

if (checkIsIOS()) {
  disableIosTextFieldZoom();
}



回答17:


After reading almost every single line here and testing the various solutions, this is, thanks to all who shared their solutions, what I came up with, tested and working for me on 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;}
}

It has some cons, though, noticeably a "jump" as result of the quick font size change occuring between the "hover"ed and "focus"ed states - and the redraw impact on performance




回答18:


Pseudo elements like :focus don't work as they used to. From iOS 11, a simple reset declaration can be added before your main styles (providing you don't override them with a smaller font size).

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

It's worth mentioning that for CSS libraries such as Tachyons.css then it's easy to accidentally override your font size.

For example class: f5 is equivalent to: fontSize: 1rem, which is fine if you have kept the body font scale at the default.

However: if you choose font size class: f6 this will be equivalent to fontSize: .875rem on a small display upwards. In that instance you'll need to be more specific about your reset declarations:


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

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

/* not small */

}




回答19:


By the way, if you use Bootstrap, you can just use this variant:

.form-control {
  font-size: 16px;
}



回答20:


I've had to "fix" the auto zoom into form controls issue for a Dutch University website (which used 15px in form controls). I came up with the following set of requirements:

  • user must still be able zoom in
  • font-size must remain the same
  • no flashes of temporary different styling
  • no jQuery requirement
  • must work on newest iOS and not hinder any other OS/device combination
  • if possible no magic timeouts, and if needed correctly clear timers

This is what I came up with so far:

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

Some notes:

  • Note that so far I've only tested it on iOS 11.3.1, but will test it on a few other versions soon
  • Use of focusIn events means it requires at least iOS 5.1 (but I see sites we build working in iOS versions older as 9 as a cool bonus anyway)
  • Using event-delegation because a lot of sites I work on have pages which might dynamically create form controls
  • Setting the eventListeners to the html element (documentElement) so as not having to wait for body to become available (don't want to bother checking if document has ready/loaded state or needing to wait for the DOMContentLoaded event)



回答21:


I see people here do some strange stuff with JavaScript or the viewport function and turning off all manually zooming on devices. That shouldn't be a solution in my opinion. Adding this CSS snippet will turn off the auto-zoom in iOS without changing your font-size to a fixed number like 16px.

By default, I use 93.8% (15px) font-size at input fields and by adding my CSS snippet this stays at 93.8%. No need to change to 16px or make it a fixed number.

input[type="text"]:focus,
textarea:focus {
    -webkit-text-size-adjust: 100%;
}



回答22:


Setting a font-size (for input fields) equal to the body's font-size, seems to be what prevents the browser from zooming out or in. I'd suggest to use font-size: 1rem as a more elegant solution.




回答23:


Even with these answers it took me three days to figure out what was going on and I may need the solution again in the future.

My situation was slightly different from the one described.

In mine, I had some contenteditable text in a div on the page. When the user clicked on a DIFFERENT div, a button of sorts, I automatically selected some text in the contenteditable div (a selection range that had previously been saved and cleared), ran a rich text execCommand on that selection, and cleared it again.

This enabled me to invisibly change text colors based on user interactions with color divs elsewhere on the page, while keeping the selection normally hidden to let them see the colors in the proper context.

Well, on iPad's Safari, clicking the color div resulted in the on-screen keyboard coming up, and nothing I did would prevent it.

I finally figured out how the iPad's doing this.

It listens for a touchstart and touchend sequence that triggers a selection of editable text.

When that combination happens, it shows the on-screen keyboard.

Actually, it does a dolly zoom where it expands the underlying page while zooming in on the editable text. It took me a day just to understand what I was seeing.

So the solution I used was to intercept both touchstart and touchend on those particular color divs. In both handlers I stop propagation and bubbling and return false. But in the touchend event I trigger the same behavior that click triggered.

So, before, Safari was triggering what I think was "touchstart", "mousedown", "touchend", "mouseup", "click", and because of my code, a text selection, in that order.

The new sequence because of the intercepts is simply the text selection. Everything else gets intercepted before Safari can process it and do its keyboard stuff. The touchstart and touchend intercepts prevent the mouse events from triggering as well, and in context this is totally fine.

I don't know an easier way to describe this but I think it's important to have it here because I found this thread within an hour of first encountering the issue.

I'm 98% sure the same fix will work with input boxes and anything else. Intercept the touch events and process them separately without letting them propagate or bubble, and consider doing any selections after a tiny timeout just to make sure Safari doesn't recognize the sequence as the keyboard trigger.




回答24:


As the automatical zoom-in (with no zoom-out) is still annonying on iPhone, here's a JavaScript based on dlo's suggestion working with focus/blur.

Zooming is disabled as soon as a text input is fucused and re-anabled when the input is left.

Note: Some users may not apprechiate editing texts in a small text input! Therefore, I personally prefer to change the input's text size during editing (see code below).

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

The following code will change an input's text size to 16 pixel (calculated, i.e., in the current zoom size) during the element has the focus. iPhone will therefore not automatically zoom-in.

Note: The zoom factor is calculated based on window.innerWidth and iPhone's display with of 320 pixels. This will only be valid for iPhone in portrait mode.

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



回答25:


It took me a while to find it but here's the best code that I found......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));
});



回答26:


Based on Stephen Walsh's answer... This code works without changing the font size of inputs on focus (which looks lame), plus it still works with FastClick, which I suggest adding to all mobile sites to help bring the "snappy". Adjust your "viewport width" to suit your needs.

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



回答27:


A comment for the top answer about setting font-size to 16px asked how that is a solution, what if you want bigger/smaller font.

I don't know about you all, but using px for font sizes is not the best way to go, you should be using em.

I ran into this issue on my responsive site where my text field is larger than 16 pixels. I had my form container set to 2rem and my input field set to 1.4em. In my mobile queries I change html font-size depending on the viewport. Since the default html is 10, my input field calculates to 28px on desktop

To remove the auto-zoom I had to change my input to 1.6em. This increased my font size to 32px. Just slightly higher and hardly noticeable. On my iPhone 4&5 I change my html font-size to 15px for portrait and back to 10px for landscape. It appeard that the sweet spot for that pixel size was 48px which is why I changed to from 1.4em (42px) to 1.6em (48px).

The thing you need to do is find the sweet spot on font-size and then convert it backwards in your rem/em sizes.




回答28:


Here is a hack I used on one of my projects:

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

Ended up with the initial styles and scale I wanted but no zoom on focus.




回答29:


Inspired by @jirikuchta 's answer, I solved this problem by adding this it of CSS:

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

No JS, and I don't notice any flash or anything.

It's worth noting that a viewport withmaximum-scale=1also works, but not when the page is loaded as an iframe, or if you have some other script modifying theviewport`, etc.




回答30:


Instead of simply setting the font size to 16px, you can:

  1. Style the input field so that it is larger than its intended size, allowing the logical font size to be set to 16px.
  2. Use the scale() CSS transform and negative margins to shrink the input field down to the correct size.

For example, suppose your input field is originally styled with:

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

If you enlarge the field by increasing all dimensions by 16 / 12 = 133.33%, then reduce using scale() by 12 / 16 = 75%, the input field will have the correct visual size (and font size), and there will be no zoom on focus.

As scale() only affects the visual size, you will also need to add negative margins to reduce the field's logical size.

With this 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%;
}

the input field will have a logical font size of 16px while appearing to have 12px text.

I have a blog post where I go into slightly more detail, and have this example as viewable HTML:
No input zoom in Safari on iPhone, the pixel perfect way



来源:https://stackoverflow.com/questions/2989263/disable-auto-zoom-in-input-text-tag-safari-on-iphone

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!