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?
- 11For all Twitter Bootstrap users landing here: see also this Github issue.Jeroen– Jeroen2015-03-08 22:15:59 +00:00Commented Mar 8, 2015 at 22:15
- 7I think @daxmacrog answer exactly answers what you want, are you willing to accept it so it can rise to the top and save lots of rework from people reading through all this? 2018 Answer: stackoverflow.com/a/46254706/172651Evolve– Evolve2018-11-14 05:17:55 +00:00Commented Nov 14, 2018 at 5:17
- 112I swear, Apple creates these anti-features just to mess with our heads.Andrew Koster– Andrew Koster2019-08-24 23:57:31 +00:00Commented Aug 24, 2019 at 23:57
- 15@AndrewKoster, I agree with you even now in 2020.Ashok– Ashok2020-02-13 11:01:16 +00:00Commented Feb 13, 2020 at 11:01
- 20August 2020, and one more time, I got back here, hoping for a miracle in the answers. See your next year. I am going to eat an apple.Marc– Marc2020-08-06 09:31:37 +00:00Commented Aug 6, 2020 at 9:31
47 Answers
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">
18 Comments
maximum-scale=1 annoyingly disables user pinch zoom. The behavior changed with iOS 10 when Apple rightly decided to ignore disabling user pinch zoom. The good news is that the setting still works to prevent automatic zoom on focus.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; } 27 Comments
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; }select:focus. Was having the same issue too.@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.
17 Comments
@media screen and (-webkit-min-device-pixel-ratio:0) and (max-device-width:1024px) to limit the effect to iPhone, but do not modify websites when viewed in Chrome.@supports (-webkit-overflow-scrolling: touch), as this css feature only exists on iOSIf 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.
18 Comments
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"/> Important: do not set minimum-scale! This keeps the page manually zoomable.
10 Comments
In summary the answer is: set the font size of the form elements to at least 16px
3 Comments
font-size: 100% value and grabs the 16px necessary.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(); } 7 Comments
addMaximumScaleToMetaViewport? Is it solely for semantic reasons?input[type='text'],textarea {font-size:1em;} 6 Comments
1em, or 100%). If you set a custom font size, you can set the font-size in your snippet to 16px to avoid auto-zooming.1em nor 1rem is a proper solution because both can be less than 16px and Safari requires at least 16px to not zoom.Inspired by @jirikuchta 's answer, I solved this problem by adding this bit 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 with maximum-scale=1 also works, but not when the page is loaded as an iframe, or if you have some other script modifying the viewport, etc.
3 Comments
Instead of simply setting the font size to 16px, you can:
- Style the input field so that it is larger than its intended size, allowing the logical font size to be set to 16px.
- 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
Comments
This worked for me on iOS Safari and Chrome. For the input selector could be set the class or id to enclose the current.
@supports (-webkit-overflow-scrolling: touch) { input { font-size: 16px; } } 4 Comments
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.
2 Comments
Using (hover: none) and (pointer: coarse) to target all touchscreen devices:
A number of answers here resort to deploying JavaScript or jQuery.
But it ought to be (and it is) entirely possible to control concerns like conditional font-presentation with CSS.
Safari Mobile requires (with good reason) that any form element, when being interacted with, must have a minimum font-size of 16px (or the visual equivalent).
Let's commit to making that well-thought-out UX apply to all touchscreen browsers.
Then we can adopt the following:
@media only screen and (hover: none) and (pointer: coarse) { input, select, textarea { font-size: 11px; } input:focus, select:focus, textarea:focus { font-size: 16px; } } The Result
When using a touchscreen device, when any of the interactive form elements above are focused on, the font-size of that form element is temporarily set to 16px.
This, in turn, disables iOS Safari Mobile auto-zoom.
User-initated pinch-zoom remains unaffected on all devices and is never disabled.
3 Comments
font-size: initial so that it will still work for users who have set a different default font size.pointer: coarse usually implies a touch interaction where you tap or swipe on a screen with your fingers or thumbs - as opposed to pointer: fine which suggests a more accurate interaction like a mouse cursor. See: developer.mozilla.org/en-US/docs/Web/CSS/@media/pointerI 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; } 3 Comments
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 :)
4 Comments
I have looked through multiple answers.\
- The answer with setting
maximum-scale=1inmetatag works fine on iOS devices but disables the pinch to zoom functionality on Android devices. - The one with setting
font-size: 16px;onfocusis too hacky for me.
So I wrote a JS function to dynamically change meta tag.
var iOS = navigator.platform && /iPad|iPhone|iPod/.test(navigator.platform); if (iOS) document.head.querySelector('meta[name="viewport"]').content = "width=device-width, initial-scale=1, maximum-scale=1"; else document.head.querySelector('meta[name="viewport"]').content = "width=device-width, initial-scale=1"; Comments
2021 solution...
OK, I've read through all the old answers but none of them worked for me. After many hours of trying different things the solution seemed simple in the end.
input{ transform: scale(0.875); transform-origin: left center; margin-right: -14.28%; } Tested on iOS/Android/Chrome on PC
This allows you to use a 14px font, if you need a different size then the scaling factor is 14/16 = 0.875 and the negative margin is (1 - 0.875) / 0.875 * 100
My input has a parent set to "display:flex" and it grows to fit the parent because it has "flex: 1 1 auto". You may or may not need this but I'm including it for completeness.
1 Comment
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" />'); } 2 Comments
This worked for me:
input, textarea { font-size: initial; } 2 Comments
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.
Comments
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.
1 Comment
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.
3 Comments
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
1 Comment
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 */ } Comments
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.
1 Comment
Using these Meta tag script code work without shrink-to-fit=no
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> OR JQuery Code
if(new RegExp('iPhone|iPad|Macintosh', 'i').test(navigator.userAgent)){ $('meta[name=viewport]').attr('content', 'width=device-width, initial-scale=1, maximum-scale=1'); // shrink-to-fit=no } Using these CSS Code does not work.
* { -webkit-text-size-adjust: none; text-size-adjust: none; } 1 Comment
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)
1 Comment
For NextJS 14 this worked for me: I've added this code to my root layout.tsx:
export const viewport: Viewport = { width: "device-width", initialScale: 1.0, maximumScale: 1.0, userScalable: false, viewportFit: "contain", }; And it helped. Not sure if it still work in Next 15, but it is a solution for Next 14 for sure.
Comments
In Angular you can use directives to prevent zooming on focus on IOS devices. No meta tag to preserve accessibility.
import { Directive, ElementRef, HostListener } from '@angular/core'; const MINIMAL_FONT_SIZE_BEFORE_ZOOMING_IN_PX = 16; @Directive({ selector: '[noZoomiOS]' }) export class NoZoomiOSDirective { constructor(private el: ElementRef) {} @HostListener('focus') onFocus() { this.setFontSize(''); } @HostListener('mousedown') onMouseDown() { this.setFontSize(`${MINIMAL_FONT_SIZE_BEFORE_ZOOMING_IN_PX}px`); } private setFontSize(size: string) { const { fontSize: currentInputFontSize } = window.getComputedStyle(this.el.nativeElement, null); if (MINIMAL_FONT_SIZE_BEFORE_ZOOMING_IN_PX <= +currentInputFontSize.match(/\d+/)) { return; } const iOS = navigator.platform && /iPad|iPhone|iPod/.test(navigator.platform); iOS && (this.el.nativeElement.style.fontSize = size); } } You can use it like this <input noZoomiOS > after you declare it in your *.module.ts
Comments
Amazing, there are dozens of answers here with javascript and viewports, and only one other mentions text-size-adjust which is what I believe is the best solution.
You can just set this to none.
Add the following CSS:
* { -webkit-text-size-adjust: none; text-size-adjust: none; } 8 Comments
text-size-adjust is still considered experimental but supported by current mobile Chrome and Safari. As always, check caniuse.com.