JavaScript: Get window width minus scrollbar width

21,842

Solution 1

Discovered a very hacky solution... by adding this before my alerts in test2.js, I get the proper width:

var p = $('body').append('<p style="height: 100%; width: 100%;"></p>');
alert(p.width());
$('body').remove('p');

And consequently, all of the alerts now have the proper width. I also don't even need overflow-y in the CSS if I do it this way. Curious why this solves it...

The real answer should be keeping the HTML and CSS as is, then using document.getElementById('scroll').clientWidth. Using clientWidth gets the viewable area minus the scrollbar width.

Solution 2

The correct answer is in this post marked as accepted: CSS media queries and JavaScript window width do not match

This is the correct code:

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' ] };
}

Solution 3

I got this somewhere and would give credit if I knew where, but this has been succesfull for me. I added the result as padding when setting the html overflow to hidden.

Problem is that the scrollbar is a feature of the browser and not the web page self. Measurement should be done dynamically. A measurement with a scrollbar and a measurement without a scrollbar will resolve into calculating the difference in width.

Found the source: http://www.fleegix.org/articles/2006/05/30/getting-the-scrollbar-width-in-pixels

scrollCompensate = function () {
    var inner = document.createElement('p');
    inner.style.width = "100%";
    inner.style.height = "200px";

    var outer = document.createElement('div');
    outer.style.position = "absolute";
    outer.style.top = "0px";
    outer.style.left = "0px";
    outer.style.visibility = "hidden";
    outer.style.width = "200px";
    outer.style.height = "150px";
    outer.style.overflow = "hidden";
    outer.appendChild(inner);

    document.body.appendChild(outer);
    var w1 = inner.offsetWidth;
    outer.style.overflow = 'scroll';
    var w2 = inner.offsetWidth;
    if (w1 == w2) w2 = outer.clientWidth;

    document.body.removeChild(outer);

    return (w1 - w2);
}

var htmlpadding = scrollCompensate();

Solution 4

The correct width of the page is given by $(document).width(). Your problem is that you're using a scroll within the div (overflow: scroll). Using $(document).width() the returned value is already discounting the visible width of the scroll, but how do you put a scroll within the div value returned is no longer the same. As the width of the scroll is not standard and varies from system to system and browser to browser, it is difficult to solve.

I suggest you remove the scroll of the div and let the browser manage this by default in the body, then yes you have the correct width.

Share:
21,842
incutonez
Author by

incutonez

Web developer that enjoys building web applications full of pizzazz. I'm a reformed Ext JS developer that's currently loving Vue.js.

Updated on November 16, 2020

Comments

  • incutonez
    incutonez over 3 years

    Ok, I thought this would be really simple, but it's turning out not to be. I think I'm just messing something up in my HTML/CSS, but here goes.

    I have a basic page like so:

    HTML

    <!DOCTYPE html>
    <html>
      <head>
        <link href='test2.css' rel="stylesheet" type="text/css" />
        <script src="http://code.jquery.com/jquery-1.10.2.js"></script>
        <script src="test2.js"></script>
      </head>
      <body>
        <div id="scroll"></div>
      </body>
    </html>
    

    test2.css

    * {
      padding: 0;
      margin: 0;
    }
    
    html, body {
      height: 100%;
      width: 100%;
    }
    
    #scroll {
      height: 100%;
      width: 100%;
      overflow: scroll;
      background-color: black;
    }
    

    test2.js

    $(document).ready(function() {
      // my resolution is 1440x900
      alert('innerwidth should be 1425');
      // all of these return 1440
      alert('body innerwidth: ' + $('body').innerWidth());
      alert('document width: ' + $(document).width());
      alert('window width: ' + $(window).width());
      alert('scroll div innerwidth: ' + $('#scroll').innerWidth());
      alert('document.documentElement.clientWidth: ' + document.documentElement.clientWidth);
      alert('document.documentElement.scrollWidth: ' + document.documentElement.scrollWidth);
    });
    

    So I've got one element on the page... a div that takes up the entire screen, or rather it should be taking up the entire screen minus the scrollbars. Now, I've been doing some snooping on how to grab the width and height of a page without the scrollbars, but unfortunately, none of them return the proper value... which makes me believe I'm missing the boat in my HTML or CSS.

    I looked at the following:

    jquery - how to get screen width without scrollbar?

    how to get the browser window size without the scroll bars

    So what I need is for a method to return the value of my viewable screen minus the respective scrollbar value... so for my width, my value should be 1425 because the scrollbar is 15 pixels wide. I thought that's what innerWidth's job was, but apparently I'm wrong?

    Can anyone provide any insight? (I'm running Firefox 24.)

    EDIT

    To add some background, I've got a blank page. I will be adding elements one by one to this page, and I need to use the width of the page when calculating the sizes for these elements. Eventually, this page will grow and grow until the scrollbar appears, which is why I'm trying to force the scrollbar there from the start, but apparently, that still doesn't do anything.

    EDIT2

    Here's something even more interesting... if I do document.getElementById('scroll').clientWidth, I get the proper innerWidth, but if I do $('#scroll').width() or $('#scroll').innerWidth(), they both return the max resolution... sounds like a jQuery bug.

  • incutonez
    incutonez over 10 years
    Well, the problem I have with this is... let's say I have a blank page, and using your knowledge, not having overflow:scroll on any elements. I use the width of the page to size elements that I add in one at a time, and eventually this page grows to where it needs a scrollbar. Well, once that scrollbar comes into the picture, all of my previous elements are sized wrong, so now I'm out of luck. Does that make sense?
  • incutonez
    incutonez over 10 years
    Hmm, this looks a bit complicated for something so simple as the width of the screen.
  • Daniel
    Daniel over 10 years
    Added some more description. It looks a bit complicated, but not really. Actually these are necessary steps. I have been breaking my head as well back then. Interesting to see these odd results in width measurements .. :-)
  • incutonez
    incutonez over 10 years
    Here's something even more interesting... if I do document.getElementById('scroll').clientWidth, I get the proper innerWidth, but if I do $('#scroll').width() or $('#scroll').innerWidth(), they both return the max resolution... sounds like a jQuery bug.
  • Daniel
    Daniel over 10 years
    I don't know if it has something to do with margins or paddings, like I do a reset when starting CSS to set these to zero. Maybe this may be interesting too. Note the outerHeight(true) .. see here
  • incutonez
    incutonez over 10 years
    Hmm, but my paddings and margins are being zeroed out. Maybe I just don't understand width/innerWidth? By the looks of that table, width shouldn't include padding, border, or margin... innerWidth should include only paddiing. So it looks like they aren't, but they do include the scrollbars... that's sort of misleading.
  • Scottie
    Scottie over 9 years
    Best answer here. Worked great!
  • pospi
    pospi over 9 years
    Sorry, doesn't work in Chrome (v39 at time of writing) - I still get the scrollbar width included