Menacing Cloud

Viewport Scale on iPhone, iPad.

This article started with a simple question. How do I get the current viewport scale in a website or web app?

While focused on the iPhone/iPad, the following JavaScript solution is as generic as possible and provides access to the current viewport scale if available.

Demo

Try a pinch-to-zoom, assuming you are on a supported device. The values below will reflect the current scale within the parameters of this page's viewport settings.

The current viewport settings are:

Note, minimum-scale does not necessarily match how far the page will zoom out. On the iPhone the page will zoom out to fill the screen and no further.

Technique

The method takes advantage of window.innerWidth variation in relation to page scale.

We assume that a browser supporting full viewport scaling also takes the modern superimposed scrollbar approach.

This assumption allows us to implement a check on screen width vs. viewport width since superimposed scrollbars do not steal space otherwise occupied by the viewport.

Once the check has been passed the calculation is a very simple one. First we need the orientation corrected screen width.

// Update viewport orientation //----------------------------- this.updateOrientation = function() { this.orientation = window.orientation; if(this.orientation === undefined) { // No JavaScript orientation support. Work it out. if(document.documentElement.clientWidth > document.documentElement.clientHeight) this.orientation = 'landscape'; else this.orientation = 'portrait'; } else if(this.orientation === 0 || this.orientation === 180) this.orientation = 'portrait'; else this.orientation = 'landscape'; // Assumed default, most laptop and PC screens. };

The viewport scale can now be calculated. Browsers that don't use a viewport magnification system deliberately return ‘undefined’ when scale is queried. This includes most desktop browsers.

// Get current scale //------------------- this.getScale = function() { this.viewportScale = undefined; // Get viewport width var viewportWidth = document.documentElement.clientWidth; // Abort. Screen width is greater than the viewport width (not fullscreen). if(screen.width > viewportWidth) { console.log('Aborted viewport scale measurement. Screen width > viewport width'); return; } // Get the orientation corrected screen width this.updateOrientation(); this.screenWidth = screen.width; if(this.orientation === 'portrait') { // Take smaller of the two dimensions if(screen.width > screen.height) this.screenWidth = screen.height; } else { // Take larger of the two dimensions if(screen.width < screen.height) this.screenWidth = screen.height; } // Calculate viewport scale this.viewportScale = this.screenWidth / window.innerWidth; return this.viewportScale; };

The code allows for an immediate scale query at any point. If monitoring it like this page you will need to keep track of pinch-to-zoom, double tap (if really keen, not implemented here) and orientation change.

The iPhone's elastic scaling animation affects viewport scale measurement. A delay was built in to ensure that the viewport bounce has settled.

// Update //-------- this.update = function(callback) { // Clear timeout if already set if(this.timeout !== undefined) { clearTimeout(this.timeout); this.timeout = undefined; } if(this.delay > 0) { // Delay compensates for viewport bounce var viewScale = this; this.timeout = setTimeout(function() { viewScale.getScale(); if(callback !== undefined) callback(); }, this.delay); } else { // Immediate scale update this.getScale(); if(callback !== undefined) callback(); } };

Usage

FlameViewportScale.getScale() gets the current viewport scale.

var viewScale = new FlameViewportScale(); var currentScale = viewScale.getScale();

You can also supply a callback function to FlameViewportScale.update() to be called once the viewport scale has been recorded after a short delay that ensures a settled viewport.

viewScale.update(function() { alert('Scale measure complete'); });

Support

This code has been tested on iPhone and iPad and works correctly.

It should work on most other modern, standards compliant mobile/tablet web browsers as well. I have not tested this and I'd be interested in other people's experiences, let me know on Twitter.

The interesting cross-over will be fullscreen browsers like Safari on OS X Lion with superimposed, non-intrusive scrollbars at maximum screen width.

Source Code

All the relevant functions are on this page.

Comments

Comments, suggestions or feedback via Optic Swerve on Twitter please.

Follow the author on Twitter.

ProtoFluid. ‘Effortless responsive web design testing’.

Previous Articles

Canvas Generated Icons. Read more.

Targeting Windows 8 Snap Mode. Read more.

CSS @viewport rule or viewport meta tag? Read more.

The Responsive Viewport. Missing piece of the responsive web design puzzle? Read more.

Getting the Viewport Scale.
Read more.

Hiding the iPhone Address Bar.
Read more.

Orientation Correct Screen Width.
Read more.

iPhone Title Modification.
Read more.

Optimising for High Pixel Density Displays.
Read more.

CSS3 Media Query Prototyping With ProtoFluid.
Read more.

AJAX Kill Switch. Version 2.
Read more.

URI Processing With JavaScript.
Read more.

Source Code

All source code is provided for free.

A standard disclaimer of warranty and limitation of liability applies.