I looking for options on how to track user zooming and panning on a page when viewed in Safari on an iPhone. Safari exposes move and gesture events, so theoretically I can keep a running tally of pan and zoom operations, but that seems like overkill since the browser must track that internally.
Is this information exposed through the Document Object Model?
When you zoom in, window.innerWidth
is adjusted, but document.documentElement.clientWidth
is not, therefore:
var zoom = document.documentElement.clientWidth / window.innerWidth;
(I've tested iOS4, without viewport
<meta>
).
However, I wouldn't rely on it for anything important. DOM viewport sizes/pixel sizes in mobile browsers are a complete mess.
According to the Safari Web Content Guide, zoom events (double tap) are not exposed, so I'm not sure how you can track this.
I do not believe this information is exposed through the DOM.
On Mobile Safari and Android, here is an accurate way to measure how much the page has been zoomed.
Try it here: http://jsbin.com/cobucu/3 - change zoom then click measure.
Technique is to add a top level div:
<body>
<div id=measurer style="position:absolute;width:100%"></div>
and use the calculation:
function getZoom(){
return document.getElementById('measurer').offsetWidth / window.innerWidth;
}
The only problem is finding a tidy way to detect that the user has changed zoom (pinch, double tap, etc). Options:
- webkitRequestAnimationFrame: very reliable, but likely to cause jankiness if using animations (due to performance hit)
- setInterval: reliable but very ugly
- touch events: look for two fingers or
double tap: ugly and maybe difficult to make 100% reliable
- window.onresize + window.onorientationchange + window.onscroll: simple but totally unreliable (Edit: and onscroll can cause performance problems in WKWebView or Mobile Safari 8 or greater).
PS: Windows Phone needs a different solution (pinch-zoom doesn't change the viewport - pinch-zoom on Windows has its own separate viewport that is not visible to javascript).
I actually think things might have moved on a little since Steve's answer, as having a look at the content guide link he provided I can see a section on Handling Multi-Touch Events and also Handling Gesture Events.
Haven't tried them yet but they look pretty promising. I'll provide an update once I've checked them out and have a demo link available...
I measure zoom this way (works on iOS only):
screenOrientedWidth = screen.width;
if (window.orientation == 90) {
screenOrientedWidth = screen.height;
}
return screenOrientedWidth / window.innerWidth;
It doesn't depend of how wide content is.
However, in iOS Safari window.innerWidth
isn't correct inside a gestureend
handler. You should defer such calculation for later execution. In GWT, I use scheduleDeferred
, but I can't say how to implement this in pure JavaScript.
If you are using any elements with location:fixed this can get complicated, as the location:fixed coordinates are relative to the unzoomed window, where window coordinates are relative to the zoomed viewport. More info: How to position a fixed-location element on IOS browser when zoomed?