Apple invented the meta viewport tag to allow developers to serve a viewport that reflected the ideal viewport on a mobile device, instead of serving a web page at the maximum resolution of the device. The new iPhone 6 has a resolution of 750 x 1334, but web pages will be served with a viewport set at 375 CSS pixels with the meta viewport tag set up correctly to ensure that text is comfortably legible.

The current best practice for a minimal meta viewport tag is:

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

This is actually wrong. It should only have to be the following:

<meta name="viewport" content="initial-scale=1" />

The initial-scale directive is supposed to cause the user agent to set the zoom level to the ideal viewport zoom level for the device, which in turn sets the viewport size to the ideal size defined for the device. Naturally, Internet Explorer showed up and ruined the party, yet again.

Internet Explorer 10 for Windows Phone sets the viewport width to the ideal width in portrait mode when initial-scale is set to 1, while all other browsers automatically adjust the width based on the orientation of the device.

This necessitated the addition of the width directive, setting the width to they keyword value device-width, which obviously returns the width of the device in CSS pixels (not the physical resolution width of the device).

However, using device-width as the viewport width has also always been wrong. Ironically, the first best practice usage of the meta viewport tag used this value without initial-scale, causing problems on several devices.

Because why would you define the viewport width as the width of the device? If you switch from portrait mode to landscape mode, the device’s width will not correspond to the width you’re now seeing, but the device’s height.

Apple has applied this strict definition to device-width, while other user agents have a more lax interpretation. Firefox, Chrome and Internet Explorer for these devices understands device-width as the width of the device in its current orientation, meaning device-width is actually the device’s CSS pixel height in landscape mode.

Confused yet?

Luckily, combining the initial-scale and width directives has the effect of the user agents choosing the largest width based on the two rules. So while initial-scale gives the largest width value for every user agent other than IE10 in either orientation, IE10 gets the larger width value when applying the device-width as the width in landscape mode.

Thus, all the user agents were happy. Until they were being used on devices that allowed the user agent to be displayed in a window smaller than the full screen. Enter the Windows 8 tablets.

With Windows 8’s so-called Snap feature (which is actually the name for it in Windows 7, but I digress), the web browser could be taking up only part of the screen. You could snap your IE11 to a width of 320 CSS pixels with another app taking up the rest of the device width.

The usefulness of device-width as a keyword value suddenly reveals itself to be useless. We don’t actually want the device width, we want to know the width of the browser’s current visual layout.

For this reason, on Windows 8 tablets, Internet Explorer simply ignores the meta viewport tag entirely because due to the best practice in use, and IE’s incorrect interpretation of the initial-scale directive, it would end up choosing the entire device width as the layout width.

Now what? CSS, that’s what.

Moving the meta viewport to CSS

To deal with the non-normative – but very necessary – practice of using a meta tag to set the viewport, W3C have proposed a new @viewport rule to move this functionality into CSS.

The working draft of this proposal, from 2011, envisions translating the meta viewport tag by essentially having user agents replace it with a style tag that parses its values into @viewport properties.

Under this scheme, the best practice meta viewport tag, with width=device-width and initial-scale=1, gets translated to:

@viewport {
zoom: 1;
width: device-width;
}

Yet, due to the inherent problem with using a value called device-width when what we actually want is the visual width of the browser window, a new editor’s draft of the CSS Device Adaptation specification does away with the device-keywords.

According to this new draft, the values device-width and device-height, used in a meta viewport tag, will now be translated to 100vw and 100vh respectively when transformed into a style tag using @viewport. These device-keywords are being dropped as valid values for use in CSS.

The new draft proposal means the best practice meta viewport tag should be interpreted by user agents as:

@viewport {
zoom: 1;
width: extend-to-zoom;
}

(Note: the extend-to-zoom keyword is only meant for internal user agent usage, and is not part of the available CSS properties for @viewport.)

This new scheme was not proposed until 2013; by that time Internet Explorer 10 and 11 were already developed.

Microsoft created a vendor prefixed version of the working draft proposal – @-ms-viewport – and added support for only two of the proposed properties: width and height.

Even though the device-width value was wrong-headed for use as the width via the meta viewport tag, Microsoft still opted to support the keyword for use with their vendor prefixed @viewport. However, you can also use %, pixel values or vw/vh.

According to Microsoft’s implementation of @-ms-viewport, this should suffice to set the viewport correctly in Windows 8 app windows:

@-ms-viewport {
width: 100%;
}

And it does. So serving the meta viewport tag to everyone else, plus this new CSS rule, should make everyone happy. Right? Enter Windows Phone 8!

Internet Explorer 10 on phones, like the other user agents on mobile, does not ignore the meta viewport tag, and thus is fine without the extra CSS definition. But since it’s IE10, it doesn’t ignore the extra CSS viewport settings meant only for Windows 8 devices.

The Windows phones interpret 100% as 100% of the device’s available resolution.  So, although we sought to get away from the device-width keyword, we have to put it back to get IE10 on Windows Phone to provide a semblance of a correct viewport:

@-ms-viewport {
width: device-width;

There’s still some issues with this on Windows Phone 8 (it doesn’t work on phones that don’t have Update 3, and still buggy after that), but it’s the only practical compromise to be made, I’m afraid. One workaround is to only serve this CSS viewport snippet if the user is on a Windows 8 non-mobile device, if you are into browser-sniffing.

The future

Peering into a new viewport future, the lay of the land right now seems to indicate that we would use the following CSS rule to set the viewport correctly for all devices:

@viewport {
width: auto; (or 100%)
}

As of right now, there doesn’t seem to be any devices that support this. Chrome on desktop, in emulation mode, seems to honor the new @viewport rule with the width set to auto, 100% or 100vw. From testing an array of phones, it doesn’t seem that setting this value will hurt anything – but nonetheless it won’t start working until these devices support it.

Thus for now, to have Windows 8 touch devices and all other devices working, you need both the meta viewport set with the best practice values, in addition to the @-ms-viewport width set to device-width.

Any guesses as to when we’ll see the meta viewport tag gone and replaced by CSS? It’s already been around for 7 years, and is ubiquitous as ever.

References: