可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I've update my iPhone 6 plus to iOS 10 beta version and just found that in mobile safari, you can zoom any webpages by double tapping or pinching IGNORE the user-scalable=no
code in the meta tag. I don't know whether it's a bug or feature. If it's considered as a feature, how do we disable viewport zooming iOS 10 safari ?
updated on iOS 11/12 release, iOS 11 and iOS 12 safari still DO NOT respect the user-scalable=no
meta tag.
回答1:
It's possible to prevent webpage scaling in safari on iOS 10, but it's going to involve more work on your part. I guess the argument is that a degree of difficulty should stop cargo-cult devs from dropping "user-scalable=no" into every viewport tag and making things needlessly difficult for vision-impaired users.
Still, I would like to see Apple change their implementation so that there is a simple (meta-tag) way to disable double-tap-to-zoom. Most of the difficulties relate to that interaction.
You can stop pinch-to-zoom with something like this:
document.addEventListener('touchmove', function (event) {
if (event.scale !== 1) { event.preventDefault(); }
}, false);
Note that if any deeper targets call stopPropagation on the event, the event will not reach the document and the scaling behavior will not be prevented by this listener.
Disabling double-tap-to-zoom is similar. You disable any tap on the document occurring within 300 milliseconds of the prior tap:
var lastTouchEnd = 0;
document.addEventListener('touchend', function (event) {
var now = (new Date()).getTime();
if (now - lastTouchEnd <= 300) {
event.preventDefault();
}
lastTouchEnd = now;
}, false);
If you don't set up your form elements right, focusing on an input will auto-zoom, and since you have mostly disabled manual zoom, it will now be almost impossible to unzoom. Make sure the input font size is >= 16px.
If you're trying to solve this in a WKWebView in a native app, the solution given above is viable, but this is a better solution: https://stackoverflow.com/a/31943976/661418. And as mentioned in other answers, in iOS 10 beta 6, Apple has now provided a flag to honor the meta tag.
Update May 2017: I replaced the old 'check touches length on touchstart' method of disabling pinch-zoom with a simpler 'check event.scale on touchmove' approach. Should be more reliable for everyone.
回答2:
This is a new feature in iOS 10.
From the iOS 10 beta 1 release notes:
- To improve accessibility on websites in Safari, users can now pinch-to-zoom even when a website sets
user-scalable=no
in the viewport.
I expect we're going to see a JS add-on soon to disable this in some way.
回答3:
It appears that this behavior is supposedly changed in the latest beta, which at the time of writing is beta 6.
From the release notes for iOS 10 Beta 6:
WKWebView
now defaults to respecting user-scalable=no
from a viewport.
Clients of WKWebView
can improve accessibility and allow users to
pinch-to-zoom on all pages by setting the WKWebViewConfiguration
property ignoresViewportScaleLimits
to YES
.
However, in my (very limited) testing, I can't yet confirm this to be the case.
Edit: verified, iOS 10 Beta 6 respects user-scalable=no
by default for me.
回答4:
I've been able to fix this using the touch-action
css property on individual elements. Try setting touch-action: manipulation;
on elements that are commonly clicked on, like links or buttons.
回答5:
I spent about an hour looking for a more robust javascript option, and did not find one. It just so happens that in the past few days I've been fiddling with hammer.js (Hammer.js is a library that lets you manipulate all sorts of touch events easily) and mostly failing at what I was trying to do.
With that caveat, and understanding I am by no means a javascript expert, this is a solution I came up with that basically leverages hammer.js to capture the pinch-zoom and double-tap events and then log and discard them.
Make sure you include hammer.js in your page and then try sticking this javascript in the head somewhere:
< script type = "text/javascript" src="http://hammerjs.github.io/dist/hammer.min.js"> < /script >
< script type = "text/javascript" >
// SPORK - block pinch-zoom to force use of tooltip zoom
$(document).ready(function() {
// the element you want to attach to, probably a wrapper for the page
var myElement = document.getElementById('yourwrapperelement');
// create a new hammer object, setting "touchAction" ensures the user can still scroll/pan
var hammertime = new Hammer(myElement, {
prevent_default: false,
touchAction: "pan"
});
// pinch is not enabled by default in hammer
hammertime.get('pinch').set({
enable: true
});
// name the events you want to capture, then call some function if you want and most importantly, add the preventDefault to block the normal pinch action
hammertime.on('pinch pinchend pinchstart doubletap', function(e) {
console.log('captured event:', e.type);
e.preventDefault();
})
});
</script>
回答6:
I tried the previous answer about pinch-to-zoom
document.documentElement.addEventListener('touchstart', function (event) {
if (event.touches.length > 1) {
event.preventDefault();
}
}, false);
however sometime the screen still zoom when the event.touches.length > 1
I found out the best way is using touchmove event, to avoid any finger moving on the screen. The code will be something like this:
document.documentElement.addEventListener('touchmove', function (event) {
event.preventDefault();
}, false);
Hope it will help.
回答7:
Check for scale factor in touchove event then prevent touch event.
document.addEventListener('touchmove', function(event) {
event = event.originalEvent || event;
if(event.scale > 1) {
event.preventDefault();
}
}, false);
回答8:
We can get everything we want by injecting one style rule and by intercepting zoom events:
$(function () {
if (!(/iPad|iPhone|iPod/.test(navigator.userAgent))) return
$(document.head).append(
'<style>*{cursor:pointer;-webkit-tap-highlight-color:rgba(0,0,0,0)}</style>'
)
$(window).on('gesturestart touchmove', function (evt) {
if (evt.originalEvent.scale !== 1) {
evt.originalEvent.preventDefault()
document.body.style.transform = 'scale(1)'
}
})
})
✔ Disables pinch zoom.
✔ Disables double-tap zoom.
✔ Scroll is not affected.
✔ Disables tap highlight (which is triggered, on iOS, by the style rule).
NOTICE: Tweak the iOS-detection to your liking. More on that here.
Apologies to lukejackson and Piotr Kowalski, whose answers appear in modified form in the code above.
回答9:
I came up with a pretty naive solution, but it seems to work.
My goal was to prevent accidental double-taps to be interpreted as zoom in, while keeping pinch to zoom working for accessibility.
The idea is in measuring time between the first touchstart
and second touchend
in a double tap and then interpreting the last touchend
as click if the delay is too small. While preventing accidental zooming, this method seems to keep list scrolling unaffected, which is nice. Not sure if I haven't missed anything though.
let preLastTouchStartAt = 0;
let lastTouchStartAt = 0;
const delay = 500;
document.addEventListener('touchstart', () => {
preLastTouchStartAt = lastTouchStartAt;
lastTouchStartAt = +new Date();
});
document.addEventListener('touchend', (event) => {
const touchEndAt = +new Date();
if (touchEndAt - preLastTouchStartAt < delay) {
event.preventDefault();
event.target.click();
}
});
Inspired by a gist from mutewinter and Joseph's answer.
回答10:
In my particular case, I am using Babylon.js to create a 3D scene and my whole page consists of one full screen canvas. The 3D engine has its own zooming functionality but on iOS the pinch-to-zoom interferes with that. I updated the the @Joseph answer to overcome my problem. To disable it, I figured out that I need to pass the {passive: false} as an option to the event listener. The following code works for me:
window.addEventListener(
"touchmove",
function(event) {
if (event.scale !== 1) {
event.preventDefault();
}
},
{ passive: false }
);
回答11:
The workaround that works in Mobile Safari at this time of writing, is to have the the third argument in adddEventListener
be { passive: false }
, so the full workaround looks like this:
document.addEventListener('touchmove', function (event) {
if (event.scale !== 1) { event.preventDefault(); }
}, { passive: false });
You may want to check if options are supported to remain backwards compatible.
回答12:
As odd as it sounds, at least for Safari in iOS 10.2, double tap to zoom is magically disabled if your element or any of its ancestors have one of the following:
- An onClick listener - it can be a simple noop.
- A
cursor: pointer
set in CSS
回答13:
Unintentional zooming tends to happen when:
- A user double taps on a component of the interface
- A user interacts with the viewport using two or more digits (pinch)
To prevent the double tap behaviour I have found two very simple workarounds:
<button onclick='event.preventDefault()'>Prevent Default</button>
<button style='touch-action: manipulation'>Touch Action Manipulation</button>
Both of these prevent Safari (iOS 10.3.2) from zooming in on the button. As you can see one is JavaScript only, the other is CSS only. Use appropriately.
Here is a demo: https://codepen.io/lukejacksonn/pen/QMELXQ
I have not attempted to prevent the pinch behaviour (yet), primarily because I tend not to create multi touch interfaces for the web and secondly I have come round to the idea that perhaps all interfaces including native app UI should be "pinch to zoom"-able in places. I'd still design to avoid the user having to do this to make your UI accessible to them, at all costs.
回答14:
Found this simple work around which appears to prevent double click to zoom:
// Convert touchend events to click events to work around an IOS 10 feature which prevents
// developers from using disabling double click touch zoom (which we don't want).
document.addEventListener('touchend', function (event) {
event.preventDefault();
$(event.target).trigger('click');
}, false);
回答15:
I checked all above answers in practice with my page on iOS (iPhone 6, iOS 10.0.2), but with no success. This is my working solution:
$(window).bind('gesturestart touchmove', function(event) {
event = event.originalEvent || event;
if (event.scale !== 1) {
event.preventDefault();
document.body.style.transform = 'scale(1)'
}
});