1012

I want to provide my visitors the ability to see images in high quality, is there any way I can detect the window size?

Or better yet, the viewport size of the browser with JavaScript? See green area here:

Flip
  • 6,233
  • 7
  • 46
  • 75
Alix Axel
  • 151,645
  • 95
  • 393
  • 500
  • 16
    What i do is, set an element usually html to 100% height and get its height. Simple works everywhere. – Muhammad Umer Oct 18 '14 at 18:49
  • 1
    @MuhammadUmer good catch! If you get frustrated getting the dimensions (and you will, on mobile phones without jQuery), you can `getComputedStyle` of the expanded `html` tag. – Dan Nov 19 '14 at 13:45
  • Also, you can use the [W](https://github.com/pyrsmk/W) library, which handles cross-browser viewport detection ;) – pyrsmk Apr 29 '16 at 13:51
  • Note that if your viewport is zoomed in, you will get lower results. – Cees Timmerman Sep 07 '22 at 09:23

17 Answers17

1654

Cross-browser @media (width) and @media (height) values 

const vw = Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0)
const vh = Math.max(document.documentElement.clientHeight || 0, window.innerHeight || 0)

window.innerWidth and window.innerHeight

  • gets CSS viewport @media (width) and @media (height) which include scrollbars
  • initial-scale and zoom variations may cause mobile values to wrongly scale down to what PPK calls the visual viewport and be smaller than the @media values
  • zoom may cause values to be 1px off due to native rounding
  • undefined in IE8-

document.documentElement.clientWidth and .clientHeight


Resources

Daan
  • 2,680
  • 20
  • 39
ryanve
  • 50,076
  • 30
  • 102
  • 137
  • 1
    Just wondering if the quirksmode link says `clientWidth` / `clientHeight` is a no-go in IE9 on mobile. Can you please clarify on that? Excellent answer by the way! Thanks! – its_me Feb 22 '13 at 13:08
  • @01100001 I am not sure about IE9. You can test by comparing the values on http://responsejs.com/labs/dimensions/ - It is correct if it matches the *@media breakpoint*. See updated answer above too. – ryanve Feb 22 '13 at 22:31
  • What's the proper way to use verge.js? I tried this: [http://pastebin.com/Qb6ucjGE](http://pastebin.com/Qb6ucjGE), but it doesn't work. If possible, please take a look. – its_me Feb 22 '13 at 23:03
  • 4
    @01100001 Replace `$` with `verge`. If you want to integrate into jQuery then do `jQuery.extend(verge)`. See: http://verge.airve.com/#static – ryanve Feb 24 '13 at 17:54
  • 1
    Oh, I missed that note in the doc. Didn't know using verge would be this easy! Thanks a lot! – its_me Feb 25 '13 at 14:03
  • 4
    Just wanted to mention that in IE8 (and perhaps others) you must have the ` ` at the top of the page in order for the code to work. – Tzury Bar Yochay May 09 '13 at 07:44
  • @TzuryBarYochay Good point. Any valid HTML or XHTML doctype seems to suffice. – ryanve May 19 '13 at 16:31
  • 6
    I'm not happy with clientWidth/Height on mobile devices, really http://tripleodeon.com/wp-content/uploads/2011/12/table.html – Dan Jul 31 '13 at 10:57
  • @ryanve: Nevermind, false alert. I was looking at it on mobile and ofc the widths are the same due to the overlay scrollbars. Do you happen to know of an alternative method for `window.innerWidth`? I'm trying to calculate the scrollbar width to solve / simplify http://stackoverflow.com/q/23504154/89771. – Alix Axel May 07 '14 at 18:32
  • @Dan: Could you explain that? – Alix Axel May 07 '14 at 18:34
  • 1
    @AlixAxel, I think that the answer above does not work on mobile. I think that most of the developers want to get virtual pixels on Retina, not physical ones. – Dan May 13 '14 at 17:50
  • 1
    Doesn't seem to work on Firefox mobile, I always get 980x480 px², regardless of zoom or orientation. – Andy Sep 18 '14 at 09:32
  • 1
    -1 It's too difficult to understand what you are trying to say after that last edit. – Levi Lindsey Oct 07 '14 at 13:52
  • unfortunately in Mobile Chrome on Android devices ```document.documentElement.clientHeight``` and ```window.innerHeight``` have the same value, wich is even different from ```window.screen.height``` ```window.screen.availHeight``` when adressbar is hidden because of digital controls (tested on nexus 5 with android lollipop ) – svassr Feb 11 '15 at 18:05
  • 43
    Unless I'm missing something, this answer is wrong. In Chrome, at least, `document.documentElement.clientHeight` returns the **page height**, while `window.innerHeight` returns the **viewport height**. Big difference. – Nate Apr 14 '15 at 15:08
  • 1
    Besides the iOS bug on older versions mentioned by Dan, there's also a weirdness on the current mobile Safari that `window.innerWidth` can in fact be larger than the actual (virtual-pixel-based) screen width, if there already is content in the DOM that is larger. In those situations, `document.documentElement.clientHeight` still returns the smaller correct viewport width. Which of course is bizarre and completely contrary to what one would expect. – John Mar 21 '16 at 17:16
  • In Firefox, `documentElement.clientHeight` and `documentElement.clientWidth`, when called from within **an SVG** document - always returns 0 for both. In Chrome they return the correct values. – Yuval A. Sep 18 '16 at 13:23
  • @YuvalA what do you mean from within an SVG document? – ryanve Sep 18 '16 at 18:07
  • 1
    @ryanve - Browsers can read/parse/display SVG documents, and Javascript can be used inside of them. – Yuval A. Sep 19 '16 at 13:09
  • 1
    @Nate confirming, in a mobile version of Chrome this code returns wrong height. – Eugene Apr 22 '18 at 20:00
  • 1
    @Nate @Eugene Does the page you tested on have a `DOCTYPE`? `DOCTYPE` is required for `document.documentElement.clientHeight` to be accurate. Otherwise can you give some example numbers? I just checked in Chrome Windows desktop and Chrome iPhone and the `.max` technique still worked. Compare to `actual("height", "px")` from https://github.com/ryanve/actual#api – ryanve Apr 25 '18 at 22:50
  • On a side note, just gotta say, this answer could be grammatically cleaner. – Kalnode Aug 29 '18 at 15:57
  • Wouldn't it make more sense to do `Min(clientHeight, innerHeight) || 0`? – Pithikos Feb 20 '19 at 17:37
  • 1
    @Pithikos No due to support because `Math.min(777, undefined)` is `NaN` – ryanve Feb 25 '19 at 22:30
  • @ryanve well you can probably add some check for that. My point is that I think the proper thing is to try and get the minimum number that is not 0. That should avoid having the scrollbars calculated in, in different browsers. i.e. `Min(Min(clientHeight || Infinity, innerHeight || Infinity) || 0)` – Pithikos Feb 26 '19 at 10:07
  • 4
    different screen size variables/solutions live test: https://ryanve.com/lab/dimensions/ – Alex P. Jun 04 '19 at 11:34
  • In my testing, `innerWidth` seems to sometimes cause style recalculation, whereas `clientWidth` doesn't. Seems counter-intuitive, but I thought I'd mention it here anyway. – Collin Anderson Jul 30 '20 at 03:08
  • The [live test site](https://ryanve.com/lab/dimensions) is trashed - it reports "undefined" for all values on Chrome 87 – user9645 Jan 15 '21 at 14:39
  • @ryanve I'm late to the party here, but in answer to `document.documentElement.clientHeight` and `...Width` seeming to be inaccurate, I'm testing on a page that does have a `DOCTYPE`, using Chrome Desktop with mobile emulation turned on, and in this scenario those numbers are wrong (significantly larger than they should be). The numbers returned by `window.innerHeight` and `...Width` are accurate. Not sure why, and it's more difficult to test on real mobile so I'm not sure about there either.. – Mike Willis Mar 17 '23 at 21:20
  • documentElement.clientHeight should be correct when the browser isn't in quirks mode according to the w3 standard. Normally the document won't be in quirks mode as long as a DOCTYPE is set, but there is questionable reference in a stack overflow post that this might not always be the case if there is malformed html. Sources: (1) https://www.w3.org/TR/2016/WD-cssom-view-1-20160317/#dom-element-clientheight (found that link as a reference from (2) https://developer.mozilla.org/en-US/docs/Web/API/Element/clientHeight) (3) https://stackoverflow.com/questions/1695787/what-is-quirks-mode – Kevin Wheeler Apr 18 '23 at 15:17
121

jQuery dimension functions

$(window).width() and $(window).height()

antony.trupe
  • 10,640
  • 10
  • 57
  • 84
Scott Evernden
  • 39,136
  • 15
  • 78
  • 84
  • 29
    This doesn't gets viewport size, but overall document size. Try it. – Alejandro García Iglesias Aug 09 '13 at 19:34
  • 3
    For browsers that display their addon toolbars as HTML with fixed postitionning, this solution is not working, especially if you want to use in your code top positionning and percentages. – Adib Aroui May 06 '14 at 14:15
  • 8
    @AlejandroIglesias: Nope, I just tested it on this SO page. `$(window).height();` returns 536, whereas `$("html").height();` returns 10599 – Flimm Jan 14 '16 at 16:33
  • 3
    Warning these dimensions do not include scrollbars (which have different sizes in different browsers and platforms) and therefore they will not match up with css media queries other answers here do however solve this problem. – Spencer O'Reilly Jun 01 '17 at 16:56
92

You can use the window.innerWidth and window.innerHeight properties.

innerHeight vs outerHeight

Rob W
  • 341,306
  • 83
  • 791
  • 678
Christian C. Salvadó
  • 807,428
  • 183
  • 922
  • 838
38

If you aren't using jQuery, it gets ugly. Here's a snippet that should work on all new browsers. The behavior is different in Quirks mode and standards mode in IE. This takes care of it.

var elem = (document.compatMode === "CSS1Compat") ? 
    document.documentElement :
    document.body;

var height = elem.clientHeight;
var width = elem.clientWidth;
Chetan S
  • 23,637
  • 2
  • 63
  • 78
  • 9
    Doesn't this give you the height of the page, not the viewport? That's what this page seems to indicate: https://developer.mozilla.org/en/DOM/element.clientHeight – allyourcode Dec 12 '09 at 23:13
  • 4
    You are using `clientHeight` on the `document.documentElement` element, which will give you the viewport size. To get the document size, you would need to do `document.body.clientHeight`. As Chetan explains, this behaviour applies to the modern browsers. It is easy to test. Just open a console and type `document.documentElement.clientHeight` on several open tabs. – Gajus Nov 07 '14 at 09:55
23

I looked and found a cross browser way:

function myFunction(){
  if(window.innerWidth !== undefined && window.innerHeight !== undefined) { 
    var w = window.innerWidth;
    var h = window.innerHeight;
  } else {  
    var w = document.documentElement.clientWidth;
    var h = document.documentElement.clientHeight;
  }
  var txt = "Page size: width=" + w + ", height=" + h;
  document.getElementById("demo").innerHTML = txt;
}
<!DOCTYPE html>
<html>
  <body onresize="myFunction()" onload="myFunction()">
   <p>
    Try to resize the page.
   </p>
   <p id="demo">
    &nbsp;
   </p>
  </body>
</html>
Ahmed Hussein
  • 715
  • 1
  • 15
  • 38
Supermath101
  • 417
  • 3
  • 10
  • note that stackoverflow's use of an iframe surrounding the code snippet messes up the result – Miller May 11 '19 at 07:43
  • 1
    Every so often I come across an answer that is a direct hit in terms of a solution and understanding how it all works. I wished I could give this 10 upvotes instead of just one. To make this work interactively using the F12 mobile simulator, I found this tag is needed in the page – pghcpa Nov 15 '20 at 22:02
  • @pghcpa I wish I could give your comment 10 upvotes instead of one. That meta tag is a lifesaver. – Coder Gautam YT Nov 24 '21 at 03:37
18

I know this has an acceptable answer, but I ran into a situation where clientWidth didn't work, as iPhone (at least mine) returned 980, not 320, so I used window.screen.width. I was working on existing site, being made "responsive" and needed to force larger browsers to use a different meta-viewport.

Hope this helps someone, it may not be perfect, but it works in my testing on iOs and Android.

//sweet hack to set meta viewport for desktop sites squeezing down to mobile that are big and have a fixed width 
  //first see if they have window.screen.width avail
  (function() {
    if (window.screen.width)
    {
      var setViewport = {
        //smaller devices
        phone: 'width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no',
        //bigger ones, be sure to set width to the needed and likely hardcoded width of your site at large breakpoints  
        other: 'width=1045,user-scalable=yes',
        //current browser width
        widthDevice: window.screen.width,
        //your css breakpoint for mobile, etc. non-mobile first
        widthMin: 560,
        //add the tag based on above vars and environment 
        setMeta: function () {
          var params = (this.widthDevice <= this.widthMin) ? this.phone : this.other; 
          var head = document.getElementsByTagName("head")[0];
          var viewport = document.createElement('meta');
          viewport.setAttribute('name','viewport');
          viewport.setAttribute('content',params);
          head.appendChild(viewport);
        }
      }
      //call it 
      setViewport.setMeta();
    }
  }).call(this);
Jazzy
  • 6,029
  • 11
  • 50
  • 74
14

I was able to find a definitive answer in JavaScript: The Definitive Guide, 6th Edition by O'Reilly, p. 391:

This solution works even in Quirks mode, while ryanve and ScottEvernden's current solution do not.

function getViewportSize(w) {

    // Use the specified window or the current window if no argument
    w = w || window;

    // This works for all browsers except IE8 and before
    if (w.innerWidth != null) return { w: w.innerWidth, h: w.innerHeight };

    // For IE (or any browser) in Standards mode
    var d = w.document;
    if (document.compatMode == "CSS1Compat")
        return { w: d.documentElement.clientWidth,
           h: d.documentElement.clientHeight };

    // For browsers in Quirks mode
    return { w: d.body.clientWidth, h: d.body.clientHeight };

}

except for the fact that I wonder why the line if (document.compatMode == "CSS1Compat") is not if (d.compatMode == "CSS1Compat"), everything looks good.

Community
  • 1
  • 1
nonopolarity
  • 146,324
  • 131
  • 460
  • 740
  • are you talking about Retina display or Landscape vs Portrait or the meta viewport tag? You don't mean virtual pixels as in http://www.snowdragonledhk.com/new-difference-between-virtual-pixels-and-real-pixels.htm ? – nonopolarity May 13 '14 at 18:31
  • 1) When talking about high-DPI displays I mean virtual pixels explained here: http://stackoverflow.com/a/14325619/139361. Every iPhone screen is exactly 320 virtual pixels wide. 2) I say that: a)`documentElement.clientWidth` does not respond on device orientation change on iOS. b) displays physical pixels count (practically useless) instead of virtual pixels – Dan May 13 '14 at 19:41
14

If you are looking for non-jQuery solution that gives correct values in virtual pixels on mobile, and you think that plain window.innerHeight or document.documentElement.clientHeight can solve your problem, please study this link first: https://tripleodeon.com/assets/2011/12/table.html

The developer has done good testing that reveals the problem: you can get unexpected values for Android/iOS, landscape/portrait, normal/high density displays.

My current answer is not silver bullet yet (//todo), but rather a warning to those who are going to quickly copy-paste any given solution from this thread into production code.

I was looking for page width in virtual pixels on mobile, and I've found the only working code is (unexpectedly!) window.outerWidth. I will later examine this table for correct solution giving height excluding navigation bar, when I have time.

jla
  • 4,191
  • 3
  • 27
  • 44
Dan
  • 55,715
  • 40
  • 116
  • 154
12

This code is from http://andylangton.co.uk/articles/javascript/get-viewport-size-javascript/

function viewport() {
    var e = window, a = 'inner';
    if (!('innerWidth' in window )) {
        a = 'client';
        e = document.documentElement || document.body;
    }
    return { width : e[ a+'Width' ] , height : e[ a+'Height' ] };
}

NB : to read the width, use console.log('viewport width'+viewport().width);

Xavier Blondel
  • 337
  • 3
  • 7
11

There is a difference between window.innerHeight and document.documentElement.clientHeight. The first includes the height of the horizontal scrollbar.

Szépe Viktor
  • 338
  • 2
  • 13
  • 1
    Did you test your answer across OSes, on Retina displays and in landscape/portrait modes? This link covers rather outdated systems, but it proves that your code does not work: http://tripleodeon.com/wp-content/uploads/2011/12/table.html – Dan May 13 '14 at 17:04
10

For detect the Size dynamically

You can do it In Native away, without Jquery or extras

console.log('height default :'+window.visualViewport.height)
console.log('width default :'+window.visualViewport.width)

window.addEventListener('resize',(e)=>{         
      console.log( `width: ${e.target.visualViewport.width}px`);
      console.log( `height: ${e.target.visualViewport.height}px`);
 });
Julio Vinachi
  • 381
  • 4
  • 8
  • Not supported by IE (any version). – Indev Jan 12 '22 at 20:15
  • 1
    IE's not supported by Microsoft (any version). It's safe to put it in a box and bury it at the end of the garden now. – Rich - enzedonline Sep 30 '22 at 13:46
  • but in the Original ask are using Firefox, Now I ask, who uses IE's? https://www.oberlo.com/statistics/browser-market-share , (ask Original) How to get the browser viewport dimensions? They never specified using IE @Indev – Julio Vinachi Oct 05 '22 at 02:43
8

A solution that would conform to W3C standards would be to create a transparent div (for example dynamically with JavaScript), set its width and height to 100vw/100vh (Viewport units) and then get its offsetWidth and offsetHeight. After that, the element can be removed again. This will not work in older browsers because the viewport units are relatively new, but if you don't care about them but about (soon-to-be) standards instead, you could definitely go this way:

var objNode = document.createElement("div");
objNode.style.width  = "100vw";
objNode.style.height = "100vh";
document.body.appendChild(objNode);
var intViewportWidth  = objNode.offsetWidth;
var intViewportHeight = objNode.offsetHeight;
document.body.removeChild(objNode);

Of course, you could also set objNode.style.position = "fixed" and then use 100% as width/height - this should have the same effect and improve compatibility to some extent. Also, setting position to fixed might be a good idea in general, because otherwise the div will be invisible but consume some space, which will lead to scrollbars appearing etc.

Firefall
  • 137
  • 1
  • 3
  • Unfortunately, the reality completely destroys your "W3C - standards solution": 1) http://caniuse.com/viewport-units , 2) http://caniuse.com/#feat=css-fixed. What developers need is the solution that works, not "should theoretically work". – Dan May 13 '14 at 17:11
  • If we can rely on the standards then we don't even need all those cross browser solutions. A solution that replies on the spec is not a solution. – Derek 朕會功夫 Oct 05 '14 at 01:11
7

It should be

let vw = document.documentElement.clientWidth;
let vh = document.documentElement.clientHeight;

understand viewport: https://developer.mozilla.org/en-US/docs/Web/CSS/Viewport_concepts

shorthand for link above: viewport.moz.one

I've built a site for testing on devices: https://vp.moz.one

initd
  • 81
  • 1
  • 5
5

This is the way I do it, I tried it in IE 8 -> 10, FF 35, Chrome 40, it will work very smooth in all modern browsers (as window.innerWidth is defined) and in IE 8 (with no window.innerWidth) it works smooth as well, any issue (like flashing because of overflow: "hidden"), please report it. I'm not really interested on the viewport height as I made this function just to workaround some responsive tools, but it might be implemented. Hope it helps, I appreciate comments and suggestions.

function viewportWidth () {
  if (window.innerWidth) return window.innerWidth;
  var
  doc = document,
  html = doc && doc.documentElement,
  body = doc && (doc.body || doc.getElementsByTagName("body")[0]),
  getWidth = function (elm) {
    if (!elm) return 0;
    var setOverflow = function (style, value) {
      var oldValue = style.overflow;
      style.overflow = value;
      return oldValue || "";
    }, style = elm.style, oldValue = setOverflow(style, "hidden"), width = elm.clientWidth || 0;
    setOverflow(style, oldValue);
    return width;
  };
  return Math.max(
    getWidth(html),
    getWidth(body)
  );
}
manolinjr81
  • 51
  • 1
  • 3
4

If you are using React, then with latest version of react hooks, you could use this.

// Usage
function App() {
   const size = useWindowSize();

   return (
     <div>
       {size.width}px / {size.height}px
     </div>
   );
 }

https://usehooks.com/useWindowSize/

Vijay122
  • 884
  • 8
  • 12
2

you can use window.addEventListener('resize' , yourfunction); it will runs yourfunction when the window resizes. when you use window.innerWidth or document.documentElement.clientWidth it is read only. you can use if statement in yourfunction and make it better.

2

You can simply use the JavaScript window.matchMedia() method to detect a mobile device based on the CSS media query. This is the best and most reliable way to detect mobile devices.

The following example will show you how this method actually works:

<script>
$(document).ready(function(){
    if(window.matchMedia("(max-width: 767px)").matches){
        // The viewport is less than 768 pixels wide
        alert("This is a mobile device.");
    } else{
        // The viewport is at least 768 pixels wide
        alert("This is a tablet or desktop.");
    }
});
</script>