31
votes

I'm working on a web app that is targeted to browsers on desktop, tablet and smartphone.

The web app has a light box implemented using Colorbox with an iframe. When the browser window is resized or the tablet/phone has it's orientation changed, Javascript code queries the window dimensions so that it can resize some elements of the light box.

The issue I'm having is that everything works fine on desktop (Windows: IE, Firefox, Chrome, Mac: Safari), iPad & iPhone but not on the Android smartphone (HTC) and Android Emulator.

Android always returns different values for screen.width, screen.height, window.innerWidth & window.innerHeight when they're queried from inside the window's resize event, which fires multiple times.

Why is the Android browser returning such a wide variance in values and how can I reliably detect the width and height of the browser window?

8
There is no reliable way (yet). However, listening to resize and waiting a few (100) milliseconds is usually enough for the properties to be set correctly in 99% of the time. It's also important to set the viewport and target dpi as meta tags. - Torsten Walter

8 Answers

17
votes

On Android, window.outerWidth and window.outerHeight are reliably the screen size. Depending on your version of Android, innerWidth/Height is usually incorrect.

Here's a really good writeup on the situation.

4
votes

Below is differentiation based on readings with Samsung Tab running Android 4.1

  • screen.height - gives actual device height including task bar and title bar

  • window.innerHeight - gives the height excluding task bar, title bar and address bar(if visible)

  • window.outerHeight - gives the height excluding task bar and title bar height, (no matter address bar is visible or hidden, outerHeight include the address bar height.)
3
votes

I'm using this to make it work between ios and android.

var screenHeight = (ionic.Platform.isIOS()) ? window.screen.height : window.innerHeight * window.devicePixelRatio;
2
votes

I took me hours to find a workaround.

The only constant among window.innerHeight, window.outerheight, etc was screen.height.

This code gave me the outerheight:

screen.height / window.devicePixelRatio - window.screenTop

Also, in order to support older versions of android, place your code in a setTimeout

I hope this is helpful =)

2
votes

Try this, and check your mobile reading

<script>
var total_height=screen.height*window.devicePixelRatio;
alert(total_height);
</script>

It should match the screen size (height) of your phone specifications.

0
votes
    var throttle = (function () {
        var timer;

        return function (fn, delay) {
            clearTimeout(timer);
            timer = setTimeout(fn, delay);
      };
    })(),


    var callback = function (w, h) {
        alert(w + ' ' + h);
    }


    window.onresize = throttle(function () {
        width = Math.min(window.innerWidth, window.outerWidth);
        height = Math.min(window.innerHeight, window.outerHeight);

        callback(width, height);
    }, 60);
0
votes

Dan's answer fix the inconcistancy between android's browser.. so I post how I detect/change mobile viewport and adapt it when rotated (don't know if usable for any one...

var lastorg=0; //set the begining of script
thisorg=parseInt(window.innerWidth)/parseInt(window.innerHeight); //for ratio to detact orietation
if(((lastorg<1 && thisorg>1) ||(lastorg>1 && thisorg<1) ||lastorg==0 )){ //is start or change
$("#viewport").attr('content', 'width=device-width, initial-scale=1,minimum-scale=1, maximum-scale=1'); // reset viewport to device
mywidth = Math.min(window.innerWidth, window.outerWidth); //Dan's way to fix the inconsistancy
myheight = Math.min(window.innerHeight, window.outerHeight);
lastorg=thisorg;    //update the lastorg
wr=parseInt(mywidth)/1280;  // the minimum desire width
hr=parseInt(myheight)/630;  // the minimum desire height
if(hr<wr){
vscale=hr;
if(hr<1){ // if it if small screen, so desktop pc wouldn't change
windowHeight=630;
windowwidth=mywidth/hr;
}
}else{
 vscale=wr;
 if(wr<1){
  windowwidth=1280;
  windowHeight=myheight/wr;
 }
}
$("#viewport").attr('content', 'width=device-width, initial-scale='+vscale+',minimum-scale='+vscale+', maximum-scale='+vscale); //reset viewport toresize window
 if(thisorg>1){
  $("#pro").fadeOut(500);
 }else{
$("body").prepend("<div id=pro style='position:absolute;width:800px;height:30px;padding:30px;left:"+(windowwidth/2)+"px;top:"+(windowHeight/2)+"px;margin-left:-430px;margin-top:-45px;;border:1px solid #555;background:#ddeeff;text-align:center;z-index:99999;color:#334455;font-size:40px;' class=shadowme>Please rotate your phone/tablet</div>");//tell user to rotate
}
}
0
votes

In my case, the setTimeout hook was not useful.

After some digging, I discover that different Android versions (and devices) have different devicePixelRatio values.

If the devicePixelRatio is equal or greater than 1, the actual number of pixels in the screen (for the html page point of view) is given by window.screen.width (or ...height).

But, if the window.screen.width is less than 1 (it happens in some old Android devices), the actual number of pixels becomes: window.screen.width/devicePixelRatio.

So, you just have to cope with this.

w = window.screen.width;
h = window.screen.height;

if(window.devicePixelRatio < 1){
  w = window.screen.width/window.devicePixelRatio;
  h = window.screen.height/window.devicePixelRatio;
}