4

The webserver wants to get info like screen size from each mobile handset that browses a webpage. The Javascript functions screen.width and screen.height return wildly inaccurate values.

Is there a way for the webserver to detect the screen size of the mobile handset? The client browser is webkit on Android.

Peter vdL
  • 4,953
  • 10
  • 40
  • 60
  • 1
    Could you give an example for highly inaccurate values? Something link "reported width/height: x/y, actual width/height: a/b". – Daniel Nov 08 '10 at 22:20
  • 1
    On a Droid X running Android 2.2, reported screen width = 800, actual screen width 480. Reported screen height = 1360, actual screen height = 854. On reloading the page, reported screen height = 1220, actual screen height still = 854 -- Peter – Peter vdL Nov 09 '10 at 00:35
  • Thanks, that's weird. It does not seem to have anything to do with the DPI of the device. – Daniel Nov 09 '10 at 17:14
  • I have updated my answer with a better example for detecting zoom level on Android and iOS (because a few users tried to edit my answer to say it wouldn't work - arrrgh). The zoom level isn't an actual answer, but it is needed for any solution that trys to use window.innerWidth. – robocat Oct 19 '12 at 00:35

3 Answers3

1

You could try using CSS media queries, which should hopefully use the correct values.

<link rel="stylesheet" type="text/css" 
media="only screen and (min-device-width: 320px)" 
href="logResolutionScript?width=320" />

Use basically the same rules for other width and heights and a cookie to check if a client loads more than one stylesheet to get the correct value. You won't get the exact resolution, but it should be close enough. You can also check for orientation and use combinations of max-/min-(device)-width. Your file might end up with quite a lot of css-imports, but you should be able to pin down the resolution of the client quite accurately, unfortunately at the cost of a few HTTP-requests.

CSS3 Media Queries (Specification)

Daniel
  • 1,798
  • 1
  • 13
  • 12
1

I found this article useful which mentions a meta tag that affects android and iPhone browsers which did what I needed:

<meta name="viewport" content="initial-scale=1.0">

From Mislav's article: What Mobile Safari does by default (i.e. without this directive) is display a zoomed-out, 980px-wide version of the page even if the layout itself is narrower. As content authors, with this directive we're saying "trust me, zoom to natural scale and I'll make sure it fits"

It seems to make the screen size and width values correct when read from JavaScript because the page is not zoomed (and if page is larger you can still scroll it). Alternatively there is probably a javascript variable to read out the zoom level.

For the iPhone this is documented here.

robocat
  • 5,293
  • 48
  • 65
0

On Android you can work out the current zoom by adding an absolute div to the body of width 100%, and dividing the div's offsetWidth by window.innerWidth.

var iPadMeasureWidthNode = window.iPadWNode;
if (!iPadMeasureWidthNode) {
    iPadMeasureWidthNode = window.iPadWNode = document.createElement('div');
    // .ipad-measure-w {position:absolute; width:100%; top:-1px}
    iPadMeasureWidthNode.className = 'ipad-measure-w';
    document.body.insertBefore(iPadMeasureWidthNode, document.body.firstChild);
}
var zoominverse = 1000 / Math.round(1000 * iPadMeasureWidthNode.offsetWidth / window.innerWidth);

You can keep an element at 1:1 zoom by inverting (undoing) the amount of zoom:

// Not using scale3d because is hardware zooming which is ugly unreadable blurry pixel magnification.
node.style.webkitTransform = (zoominverse > 1) ? 'scale(' + zoominverse + ')' : '';
node.style.webkitTransformOrigin = (zoominverse > 1) ? '0 0 0' : '';

Zoom change is detected by window.onresize event (although resize event is delayed until after resize is completed... you can detect zoom start using the gesturestart event on iPad, or document.touchstart event and detect 2 fingers down).

Edit: After three corrections saying it doesn't work, I thought I better add an example showing it working. Tested works on: Android 4.1.2 normal browser, Android 4.1.2 Chrome, Android Opera Mobile 12.10, iPad 2 iOS4. (Didn't work on Android Firefox Mobile, and won't work in an iframe so jsfiddle won't work).

<!DOCTYPE html>
<html>
<head>
<style>
.ipad-measure-w {
    position: absolute;
    width: 100%;
    top: -1px;
};
</style>
</head>
<body>
<button onclick="alertWidth()">alertWidth</button>
<div style="width: 1600px;  height: 100px; background-color: blue;"></div>
<script>
function alertWidth() {
    var iPadMeasureWidthNode = window.iPadWNode;
    if (!iPadMeasureWidthNode) {
        iPadMeasureWidthNode = window.iPadWNode = document.createElement('div');
        iPadMeasureWidthNode.className = 'ipad-measure-w';
        document.body.insertBefore(iPadMeasureWidthNode, document.body.firstChild);
    }
    var zoominverse = 1000 / Math.round(1000 * iPadMeasureWidthNode.offsetWidth / window.innerWidth);
    alert(zoominverse);
}
</script>
</body>
</html>
robocat
  • 5,293
  • 48
  • 65
  • FYI: zoom change on IE6/7/8 and maybe 9 is detected by looking for change in screen.deviceXDPI screen.deviceYDPI in window onresize event (just noticed code - it is useful to know if you need it! e.g. when IE screws up layout due to zoom change can force relayout). – robocat May 31 '12 at 03:57
  • Also on Webkit, see the window.devicePixelRatio (fixed value. 1 normally. 2 for Retina displays, 1.5 or 2 or 2.25 for Android high density displays) http://www.quirksmode.org/blog/archives/2012/06/devicepixelrati.html – robocat Oct 19 '12 at 00:37