Meta-viewport Published almost 8 years ago

The misery of meta viewport tag

Creating a mobile site layout requires not only an additional CSS file but also a viewport meta tag to specify the scale and width of the site on mobile screens. The problem arises when you add iPads and other tablets to the collection...

The tag itself

If you're using fluid layout for handhelds - which is what you usually do due to limited screen space (at least I did with this website) - you often have to use viewport meta to specify that width of the website should be the width of device. That can be accomplished via width=device-width. This makes paragraphs wider (and not just upscaled) in landscape orientation etc.

You also often disable the ability to scale with pinch gesture as this makes no sense with fluid layout. This is accomplished via initial-scale=1.0, user-scalable=no.

Unfortulately, this completely kills the layout on tablets on which you may want to display normal (usually fixed-width) desktop layout and so above viewport settings screw things up.

Why? user-scalable should be set to user-scalable=yes and width should be fixed to layout width like width=950 or shouldn't be specified at all as iPad handles that part on its own. If you load 950px-wide page with width=device-width on iPad, it will appear noticably wider or narrower than the browser window - depending on orientation. Orientation change gets screwed up too. Its obvious that the same viewport tag cannot be used for handhelds and tablets

The problem

The problem is it is! That's right, the same meta viewport tag gets applied both to handhelds (like iPhone and Android phones) and to tablets (both iPads and Tabs or other Android excuses for a tablet).

No matter how hard I try to figure it out, it eludes me how the hell can the same viewport tag be applied to completely different kinds of devices with completely different screen sizes and browser experiences. And there's really no way to appy the tag selectively - like we can (and do) with stylesheets via media attribute.

The solution

Anyway, I have came with a solution based on both Javascript and server-side code. In my case, I've used my usual tools which is:

  • jQuery + CoffeeScript for Javascript
  • Rails code on server side

Fear not, this can be easily applied to plain JS and any cookie-enabled server as well.

Step 1:

Detect handhelds

I do this by applying separate CSS stylesheet to handhelds only and setting some hidden element's style to indicate that the CSS was applied. In order to appy CSS to handhelds only, you use:

= stylesheet_link_tag 'separate_iphone', :media => 'handheld, only screen and (max-device-width: 480px)'

And in the separate_iphone.css:

#platform_indicator {
  white-space: nowrap !important;

Next, I detect this hidden element's style in jQuery (included after the tag above):

platform_indicator = $("#platform_indicator").css("white-space")
onPhone = platform_indicator == 'nowrap'  

Yes, I could've used the request user agent string but that may have resulted with handheld detection inconsistent with the one that occurs by using media property of CSS include tag.

Step 2:

Handle that damn meta

The default is an empty meta, with which tablet layout works out-of-box. So this goes into main website header:

<meta name="viewport" content="" id="viewport-meta-tag" />  

In jQuery I fill this tag with handheld-centric values if handheld was detected:

if onPhone 
  meta = $("#viewport-meta-tag")
  if meta.size() > 0
    meta.attr("content", "width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no")
  $.cookie('is_on_phone', 'y')

That last line uses the jquery.cookie library and is optional. It will be needed for the last step which is also optional. Without it, phones will apply proper viewport settings with small but noticable delay, inferred by loading and executing CSSes and JS.

Step 3:

Make it perfect

Thanks to setting the cookie on handheld detection in jQuery, we can now generate proper tag on server and remove the delay between the page first appearing and applying the meta tag in mobile browsers.

I achieved it by replacing the empty meta tag from step 2 with following Rails/HAML code:

- if cookies['is_on_phone'] == 'y'
  %meta{:name => "viewport", :content => "width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"}
- else
  %meta{:name => "viewport", :content => "", :id => "viewport-meta-tag"}

This way, we can serve the correct meta on each request.

If a user has cookies disabled, she'll just have to experience the lag of JS. And if she'll have JS disabled, the correct meta won't get served. That's a problem but there's really no way around it until we get the media property for this retarded meta.

Be done with it

Or maybe some complaints submitted to Apple or some webkit developers would be in place? It would be sooo simple to just use the media attribute like with CSS. I'm not sure who exactly should I report this to. Also, I come to realise this omission is so obvious that maybe it's "by design" and reporting issues would be out of place?
For now, described method will suffice.

UPDATE: We can enhance support for users with JS disabled on handhelds by adding some user-agent detection to the conditional statement, but - as mentioned above - that may lead to inconsistent behavior.


This post has not been commented by anyone yet.

Your five cents