Orientation and scale

Paul Irish,Divya ManianandShi ChuanlaunchedMobile Boilerplaterecently—a mobile companion site toHTML5 Boilerplate.

There’s some good stuff in there but I was a little surprised to see that themeta viewportelement included values forminimum-scale=1.0, maximum-scale=1.0, user-scalable=no:

<meta name= "viewport" content= "width=device-width, target-densitydpi=160dpi, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" >

Settinguser-scalable=nois pretty much the same as settingminimum-scale=1.0, maximum-scale=1.0.In any case,I’m not keen on it.Like Roger,I don’t think we should take away the user’s right to pinch and zoom to make content larger. That’s why my usual viewport declaration is:

<meta name= "viewport" content= "width=device-width, initial-scale=1" >

Yes, I know that most native apps don’t allow you to zoom but I see no reason to replicate that failing on the web.

But there’s a problem. Allowing users to scale content for comfort would be fine if it weren’t fora bug in Mobile Safari:

When the meta viewport tag is set tocontent= "width=device-width,initial-scale=1",or any value that allows user-scaling, changing the device to landscape orientation causes the page to scale larger than 1.0. As a result, a portion of the page is cropped off the right, and the user must double-tap (sometimes more than once) to get the page to zoom properly into view.

This is really annoying soShi Chuan set about fi xing the problem.

His initial solution was to keepminimum-scale=1.0, maximum-scale=1.0in themeta viewportelement but then to change it using JavaScript once the user initiates a gesture (thegesturestartevent is triggered as soon as two fingers are on the screen). At the point, thecontentattribute of themeta viewportelement gets updated to readminimum-scale=0.25, maximum-scale=1.6,the default values:

var metas = document.getElementsByTagName('meta');
var i;
if (navigator.userAgent.match(/iPhone/i)) {
document.addEventListener( "gesturestart", gestureStart, false);
function gestureStart() {
for (i=0; i<metas.length; i++) {
if (metas[i].name == "viewport" ) {
metas[i].content = "width=device-width, minimum-scale=0.25, maximum-scale=1.6";
}
}
}
}

That works nicely but I wasn’t too keen on the dependency between the markup and the script. If, for whatever reason, the script doesn’t get executed, users are stuck with an unzoomable page.

I suggestedthat the script should alsosetthe initial value tominimum-scale=1.0, maximum-scale=1.0:

var metas = document.getElementsByTagName('meta');
var i;
if (navigator.userAgent.match(/iPhone/i)) {
for (i=0; i<metas.length; i++) {
if (metas[i].name == "viewport" ) {
metas[i].content = "width=device-width, minimum-scale=1.0, maximum-scale=1.0";
}
}
document.addEventListener( "gesturestart", gestureStart, false);
}
function gestureStart() {
for (i=0; i<metas.length; i++) {
if (metas[i].name == "viewport" ) {
metas[i].content = "width=device-width, minimum-scale=0.25, maximum-scale=1.6";
}
}
}

Now the markup still contains the robust accessible default:

<meta name= "viewport" content= "width=device-width, initial-scale=1" >

…while the script takes care of initially setting the scale values and also updating them when a gesture is detected. Here’s what’s happening:

  1. By default, the page is scaleable because the initialmeta viewportdeclaration doesn’t set aminimum-scaleormaximum-scale.
  2. Once the script loads, the page is no longer scalable because bothminimum-scaleandmaximum-scalehave been set to1.0.If the device is switched from portrait to landscape, the resizing bug won’t be triggered because scaling is disabled.
  3. When thegesturestartevent is detected—indicating that the user might be trying to scale the page—theminimum-scaleandmaximum-scalevalues are updated to allow scaling. At this point, if the device is switched from portrait to landscape, the resizing bugwilloccur because the page is now scaleable.

Jason Weaverpoints out thatyou should probably detect for iPad too.That’s a pretty straightforward update:

if (navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPad/i))

Mathias Bynensupdated the codeto usequerySelectorAllwhich is supported in Mobile Safari. Here’s the code I’m currently using:

if (navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPad/i)) {
var viewportmeta = document.querySelector('meta[name= "viewport" ]');
if (viewportmeta) {
viewportmeta.content = 'width=device-width, minimum-scale=1.0, maximum-scale=1.0';
document.body.addEventListener('gesturestart', function() {
viewportmeta.content = 'width=device-width, minimum-scale=0.25, maximum-scale=1.6';
}, false);
}
}

You can try it out onHuffduffer,Salter Cane,Principia Gastronomicaand right here onAdactio.

Right now there’s still a little sluggishness between the initial pinch-zoom gesture and the scaling; the scale values (0.25 - 1.6) don’t seem to take effect immediately. A second pinch-zoom gesture is often required. If you have any ideas for improving the event capturing and propagation, dive in there.

Update:the bug has beenfixed in iOS 6.

Have you published a response to this?:

Related posts

Upgrades and polyfills

Apple’s policy of locking browser updates to operating system updates is bad for the web and bad for the planet.

Web Audio API update on iOS

The behaviour is more consistent now.

Web Audio API weirdness on iOS

Fi xing a heisenbug with silence.

Related links

Making a ‘post-it game’ PWA with mobile accelerometer API’s | Trys Mudford

I made an offhand remark at the Clearleft Christmas party and Trys ran with it…

Tagged with

A Fix for the iOS Orientationchange Zoom Bug | Filament Group, Inc., Boston, MA

That Scott is one smart cookie. He has come up with a workaround (using the accelerometer) for that annoying Mobile Safari orientation/zoom bug that I blogged about recently.

I still want Apple to fix this bug as soon as possible—the fact that such smart people are spending so much effort on ingenious hacks shows just how much of a pain-point this is.

Tagged with

Enable/unmute WebAudio on iOS, even while mute switch is on

Remember when I wrote aboutWeb Audio weirdness on iOS?Well, this is a nice little library that wraps up the same hacky solution that I ended up using.

It’s always gratifying when something you do—especially something that feels so hacky—turns out to be independently invented elsewhere.

Tagged with

Tagged with

Previously on this day

19 years ago I wrote When mashups attack

Starring George Clooney.

22 years ago I wrote Cog movie

Forget Russian Ark; here’s a really impressive one-shot movie.