Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Making Sense of Android meta-viewport scaling: What am I missing?

I have been trying to determine how the viewport -- and the contents within -- are affected by the viewport meta tag used for drawing content with WebView or with the native browser.

What I have run in to are some apparent inconsistencies. I created a small page (see below) with an image and some javascript for displaying the viewport size so I can visually see the scaling with the image as well as get the exact numbers.

First, a some observations:

  1. None of the viewport width numbers are exactly what I expected, just close.
  2. When the numbers are close to the device pixel count, the drawing is actually done one-for-one -- or at least is visibly looks that way.
  3. If the page size (document size) is under that of the viewport size, the viewport numbers shrink. That is, the viewport doesn't always necessarily represent the maximum possible visible space -- just the current visible space.
  4. Likewise, in the native browser, the viewport size is adjusted by the top bar. The size increases as it scrolls off the screen. The numbers given are for full screen display.

Device #1: Physical screen is 1024x600 and it's running Android 2.2.

  1. initial-scale=1.0 => 676x400
  2. initial-scale=1.0, width=device-width => 676x400
  3. initial-scale=2, width=device-width => 338x200
  4. initial-scale=2, width=device-width, target-densitydpi=device-dpi => 507x300
  5. initial-scale=0.5, width=device-width, target-densitydpi=device-dpi => 800x473
  6. initial-scale=0.9, width=device-width, target-densitydpi=device-dpi => 800x473
  7. width=device-width, target-densitydpi=device-dpi => 1014x600
  8. initial-scale=1.0, width=device-width, target-densitydpi=device-dpi => 1014x600
  9. initial-scale=0.5, width=device-width, target-densitydpi=device-dpi, minimum-scale=0.1 => 2028x768
  10. initial-scale=0.5, width=device-width, target-densitydpi=device-dpi, minimum-scale=0.1, user-scalable=no => 1014x600

Device #2: Physical screen is 800x480 and it's running Android 2.3.2.

  1. initial-scale=1.0 => 527x320
  2. initial-scale=1.0, width=device-width => 527x320
  3. initial-scale=2, width=device-width => 263x160
  4. initial-scale=2, width=device-width, target-densitydpi=device-dpi => 395x240
  5. initial-scale=0.5, width=device-width, target-densitydpi=device-dpi => 790x480
  6. initial-scale=1.0, width=device-width, target-densitydpi=device-dpi => 790x480
  7. initial-scale=0.5, width=device-width, target-densitydpi=device-dpi, minimum-scale=0.1 => 1580x768
  8. initial-scale=0.5, width=device-width, target-densitydpi=device-dpi, minimum-scale=0.1, user-scalable=no => 790x480
  9. width=1580, target-densitydpi=device-dpi => 790x480
  10. width=1580, target-densitydpi=device-dpi => 790x480
  11. width=1580, target-densitydpi=device-dpi, minimum-scale=0.1 =>790x480

Of these results, the following don't make sense:

  1. Device #1, items 5, 6, and 10
  2. Device #2, items 5, 8, 10, 11, 12

Does anyone know what's going on with those that don't make sense?

Does anyone know why many of the values are 10 pixels shy of match the physical pixels, but that result is as if they match? (e.g. 1.7 and 2.6)

Am I doing something wrong, or does it appear that it's impossible to zoom out beyond 1.0 unless the user is also allowed to scale and the minimum-scale value is set?

That is, even though the valid values are 0.01 to 10, initial-scale values under 1.0 are ignored unless you can also set the minimum scale.

The Android docs do say when user-scalable is no that the min/max scale values are ignored. That doesn't seem very useful. And 2.9-2.11 seem to show that you can't just calculate it yourself and set the width.

Finally, the HTML I'm using:

<html> <script src="http://code.jquery.com/jquery-1.4.4.js"></script> <head>     <meta name="viewport" content="initial-scale=0.5, width=device-width, target-densitydpi=device-dpi, minimum-scale=0.1, user-scalable=no" /> </head> <body style="margin:0;"> <div id="bld" class="bld" style="position:absolute; width:250px; height:125px; left:50px; background-color:#ccccff;">Hello world.</div> <img id="bl1" src="http://commondatastorage.googleapis.com/kf6nvr/images/1024x768.png" /> <script>  $("#bl1").click(function(){     var pageWidth = $(document).width();     var pageHeight = $(document).height();     var viewportWidth = $(window).width();     var viewportHeight = $(window).height();       $("#bld").html("Page width: "+pageWidth+"<br />pageHeight: "+pageHeight+"<br />port width: "+viewportWidth+"<br />port height: "+viewportHeight); }); </script>  </body> </html> 

So... what am I missing?

like image 695
lilbyrdie Avatar asked Feb 03 '11 23:02

lilbyrdie


People also ask

What happens without the viewport meta element when using a mobile device?

Without a viewport meta tag, mobile devices render pages at typical desktop screen widths and then scale the pages down, making them difficult to read. Setting the viewport meta tag lets you control the width and scaling of the viewport so that it's sized correctly on all devices.

Is meta viewport necessary?

So yes, the meta viewport tag should be used on all websites and is mandatory if you want a good user experience. You may also need to use media queries to change CSS for different screen widths, like collapsing a menubar into a hamburger menu.

What does the viewport meta tag tell the browser?

This gives information such as viewport width on portrait and landscape orientation as well as physical screen size, operating system and the pixel density of the device.

Why is the viewport meta tag used in responsive web design?

The HTML Viewport meta tag is used for creating responsive website. So that web page can adjust its width according to viewport.


1 Answers

Interesting can of worms you've opened up there. As you try out more devices you'll probably see even more weirdness, and random bugs. Interesting times! :-)

I suspect that somewhere down the line you might want to give up, and just try to...

  • Stick with as simple settings as possible.
  • Accept the pixel width the device chooses to report.
  • Rely on adaptive/fluid layout and relative widths to make things work across different screen widths.
  • Use native CSS properties for a resolution neutral rendering of rounded corners, shadows and gradients.
  • Use vector formats (svg, icon-fonts, etc.) as much as possible
  • and (important) Use high-res border-images as well as background-images coupled with the well-supported background-size property1 to make things render nice and crisp2.

1) To provide backwards compatibility to older browsers (like MSIE8) you'll need to use double background-image declarations - like:

background-image: url(low-res.png);        /* CSS2 */ background-image: url(high-res.png), none; /* CSS3 */ background-size:  100px 10px;             /* CSS3 */ 

2) The -webkit-max-device-pixel-ratio media query may also help, but as the name implies it only works for webkit browsers.


Ramble:

The new generation Android and iOS devices have such varying screen DPIs that they've resorted to reporting CSS pixels rather than actual device pixels. This is both good or bad - depending on how you look at it.

It's bad because you're not guaranteed anymore the down-to-the-device-pixel control you were used to having, working with the mostly homogenous screens of yore.

On the other hand, it's good because you know your designs will never render so tiny that they can't be read/used by regular humans.

The problem with using target-densitydpi=device-dpi is that it while it works wonders on a 7inch wide 800px screen, it will completely ruin your application on a 4inch wide 960px screen.

like image 120
Már Örlygsson Avatar answered Nov 07 '22 12:11

Már Örlygsson