What size is my viewport?
Using JavaScript to get the actual viewport width
Responsive Web design is making a positive and lasting impact to the web as we know it. Along with most change comes new scenarios. I think it's safe to say that supporting a flexible viewport is at the top of the list. While CSS if often enough, sometimes JavaScript is required. Currently, there are several outdated and incorrect ways to get the viewport size using JavaScript. Many people use the innerWidth
of the browser window, while others use the clientWidth
of the documentElement
. Others use jQuery's $(window).width()
, which ends up just using documentElement.clientWidth
. Unfortunately, these approaches are flawed if what you are wanting is the actual size used in CSS media queries. To reduce confusion, I will refer to this as "CSS viewport".
Browser differences
Cross-browser compatibility still remains an issue with many features, CSS viewport size is no exception. For example, WebKit browsers change the size of their CSS viewport when scroll bars are visible, while most other browsers do not. Since window.innerWidth
remains constant regardless of the scroll bar state, it's not a good option for use with Chrome or Safari. Additionally, Internet Explorer 6, 7, and 8 do not support window.innerWidth
. On the other hand, document.documentElement.clientWidth
can change based on the scroll bar state and therefore is not a good option for Internet Explorer, Firefox, or Opera.
window.innerWidth vs. documentElement.clientWidth
If you are using window.innerWidth
to get the size the viewport irrespective to scroll bar state, then great. Or, if you are using documentElement.clientWidth
to get what the current usable viewport is, then awesome. However, if you are using one or the other thinking it will give you the actual CSS, then it's probably time to start updating your sites.
The following table compares the potential values of innerWidth
and clientWidth
to the actual CSS viewport width.
Browser | .innerWidth | .clientWidth |
---|---|---|
IE | == | <= |
Firefox | == | <= |
Opera | == | <= |
Chrome | >= | == |
Safari | >= | == |
The following table shows a more detailed comparison on how browsers treat the CSS viewport when scroll bars are visible.
Browser | @media | My script | .innerWidth | .clientWidth |
---|---|---|---|---|
IE 9 | 500 | 500 | 500 | 483 |
IE 6, 7, 8 | NA | 484 | undefined | 484 |
FF 17 Win | 500 | 500 | 500 | 483 |
FF 17 Mac | 500 | 500 | 500 | 485 |
Chrome 24 Win | 483 | 483 | 500 | 483 |
Safari 5 Win | 483 | 483 | 500 | 483 |
Opera 12 Win | 500 | 500 | 500 | 483 |
Opera 12 Mac | 500 | 500 | 500 | 485 |
Is there a good solution?
A quick web search will bring back lots of misinformation on obtaining the CSS viewport size. After looking at the actual data, the quick and dirty solution to the problem is to use user agent detection to toggle between innerWidth and clientWidth, but as we all know UA detection should only be used as a last resort (unless you are actually targeting the UA). I analyzed a lot of different JavaScript objects to find a way to calculate the CSS viewport size cross browser without UA sniffing, but with no luck. That however did not cause me to give up; if it can be done with CSS, then it should be able to be done with JavaScript. This concept led me to my current solution.
Solution
I found that if scroll bars are not visible, then window.innerWidth
and documentElement.clientWidth
will both return the correct value. However, when scroll bars are visible some additional detection is required. The current version of the script injects a CSS media query to test if documentElement.clientWidth
is equal to the current CSS viewport size. If they are equal, it uses the value, however if they are not equal, it falls back to use window.innerWidth
. There are currently no known unsupported browsers and should be ready for production use. Check out the project homepage to download the uncompressed or minified versions of the script. Enjoy!
Related
Do you know what your viewport width is? Test your knowledge.
Also, checkout my ViewportTester bookmarklet that makes viewing your viewport size easy.
And yes, I'm aware that I posted a similar script in an earlier post but thought it deserved a bit more of an explanation.