21

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?

Jason Kester
  • 5,951
  • 9
  • 35
  • 40

6 Answers6

28

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.

Kornel
  • 97,764
  • 37
  • 219
  • 309
  • Thanks for that. It's a hack, but it sounds like it might actually work, which is at least something. – Jason Kester Jun 25 '10 at 18:35
  • 3
    Just pointing out here (so maybe one fewer doc run is needed) that `document.documentElement.clientWidth` does not include the scrollbars, while `window.innerWidth` does. Same for height. – icedwater Nov 21 '13 at 02:52
  • Ignoring scrollbars, for Safari 10, its var zoom = document.documentElement.clientWidth / window.outerWidth; – uchuugaka Nov 07 '16 at 11:52
  • I meant: window.outerWidth / document.documentElement.clientWidth – uchuugaka Nov 07 '16 at 11:53
3

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

Edit: Android Visual Viewport resize and scroll events may help? See https://developer.mozilla.org/en-US/docs/Web/API/VisualViewport#Events

robocat
  • 5,293
  • 48
  • 65
  • Tested in an iPhone worked almost perfectly. The function did not detect the zoom in some occasions. Especially when doing big zoom-ins. – Sergio Mar 21 '19 at 05:12
2

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.

Steve Madsen
  • 13,465
  • 4
  • 49
  • 67
1

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

Josh Lee
  • 171,072
  • 38
  • 269
  • 275
Damon Oehlman
  • 481
  • 4
  • 5
0

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.

kirikaza
  • 2,659
  • 2
  • 15
  • 14
0

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?

Peter Hollingsworth
  • 1,870
  • 1
  • 18
  • 18