188

How can I determine the height of a horizontal scrollbar, or the width of a vertical one, in JavaScript?

Stephen Kennedy
  • 20,585
  • 22
  • 95
  • 108
glmxndr
  • 45,516
  • 29
  • 93
  • 118
  • 2
    Here is a snippet from the author of the JQuery Dimension plugin. http://github.com/brandonaaron/jquery-getscrollbarwidth/blob/master/jquery.getscrollbarwidth.js maybe late to give this solution, but it seems a better one to me, IMO. – Yanick Rochon Aug 09 '10 at 15:17
  • Have a look at this solution: http://davidwalsh.name/detect-scrollbar-width – GibboK Apr 21 '15 at 12:27
  • @GibboK -- that solution fails -- the offsetWidth == clientWidth so it's always zero. This is tested in edge IE && Chrome. – beauXjames Aug 20 '15 at 14:05
  • 1
    @beauXjames weird it works for me on FF – GibboK Aug 20 '15 at 14:28
  • This question arises in the situation in which the scrollbar is in the wrong location (somewhere in the middle of the screen). In this situation you probably do not want to show a scrollbar. In most cases I have found iScroll to be the perfect design-neutral solution for the situation: http://iscrolljs.com – Mr. Hugo May 19 '16 at 18:59

25 Answers25

150

From Alexandre Gomes Blog I have not tried it. Let me know if it works for you.

function getScrollBarWidth () {
  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);
};
Matthew Vines
  • 27,253
  • 7
  • 76
  • 97
  • 2
    The idea is genius, I'm definitely making a MooTools class based on this. – Ryan Florence Jun 12 '09 at 14:40
  • Yeah I got the same google result. :) I'm trying and keep you informed. – glmxndr Jun 12 '09 at 14:50
  • if you change your theme to one with different sized scroll bars what is the deviance in calculated to actual? – Matthew Vines Jun 12 '09 at 16:35
  • Changed the theme to Extra Large in windows, double checked in Normal size, the computation seems correct. I apparently counted wrongly. – glmxndr Jun 13 '09 at 12:31
  • 1
    see here for cross reference : http://stackoverflow.com/questions/3417139/how-do-i-calculate-the-height-of-toolbars-address-bars-and-other-navigation-tool/3417992#3417992 – Yanick Rochon Aug 05 '10 at 18:42
  • windows xp with ff7.0.1 requires `scr.style.overflow = 'auto';` you can add this under yet another another `if (w1 == w2)` in the above code – mulllhausen Nov 08 '11 at 07:44
  • 6
    Returns different values with different page zoom. Win7, Opera, FF. – Kolyunya Mar 07 '13 at 08:59
  • `position: absolute` on the `div` assigned to variable `outer`, as well as `left` and `top`, are doing nothing and can be removed. They will only have effect if `body { position: relative; }` is set. Also it is completely pointless to affix a value of `0` with `px`. – richardjsimkins Dec 03 '16 at 20:11
  • Note that I got a width of 0.0003 in my mobile Chrome, beware of comparing to zero, better do something like `>= 1`. – Paul Jul 29 '23 at 22:39
85

Using jQuery, you can shorten Matthew Vines answer to:

function getScrollBarWidth () {
    var $outer = $('<div>').css({visibility: 'hidden', width: 100, overflow: 'scroll'}).appendTo('body'),
        widthWithScroll = $('<div>').css({width: '100%'}).appendTo($outer).outerWidth();
    $outer.remove();
    return 100 - widthWithScroll;
};
Joshua Bambrick
  • 2,669
  • 5
  • 27
  • 35
  • 2
    Thanks, this solution is very clean!! – jherax Apr 24 '14 at 03:47
  • 4
    Would this solution really feel cleaner if the entire source code for JQuery was copy pasted before it? Because that's pretty much what this solution is doing. This question did not ask for an answer in JQuery, and it is perfectly possible and efficient to perform this task without the use of a library. –  Aug 19 '17 at 17:19
  • 8
    If you are already using JQuery, then Daemon's comment is irrelevant. Yes, to add JQuery just to do this would be nonsense, but to those already using JQuery in their project, this is a much 'simpler' solution than the accepted one. – Tyler Dahle Dec 05 '17 at 17:14
27

For me, the most useful way was

(window.innerWidth - document.documentElement.clientWidth)

with vanilla JavaScript.

enter image description here

Andrew Marshall
  • 95,083
  • 20
  • 220
  • 214
Andrés Moreno
  • 597
  • 5
  • 7
  • 9
    Just what I needed. One suggestion: The second term can be replaced with `document.documentElement.clientWidth`. `documentElement` more clearly and cleanly expresses the intention of getting the `` element. – Jan Miksovsky Aug 06 '18 at 17:37
  • best, simplest solution if your using JS! – benmneb Aug 28 '21 at 09:40
  • This gives `0` if the window does not already have a vertical scrollbar. This may or may not be what you want. – Pang Dec 30 '22 at 08:10
25

if you are looking for a simple operation, just mix plain dom js and jquery,

var swidth=(window.innerWidth-$(window).width());

returns the size of current page scrollbar. (if it is visible or else will return 0)

Beep.exe
  • 1,368
  • 12
  • 21
25

This is only script I've found, which is working in webkit browsers ... :)

$.scrollbarWidth = function() {
  var parent, child, width;

  if(width===undefined) {
    parent = $('<div style="width:50px;height:50px;overflow:auto"><div/></div>').appendTo('body');
    child=parent.children();
    width=child.innerWidth()-child.height(99).innerWidth();
    parent.remove();
  }

 return width;
};

Minimized version:

$.scrollbarWidth=function(){var a,b,c;if(c===undefined){a=$('<div style="width:50px;height:50px;overflow:auto"><div/></div>').appendTo('body');b=a.children();c=b.innerWidth()-b.height(99).innerWidth();a.remove()}return c};

And you have to call it when document is ready ... so

$(function(){ console.log($.scrollbarWidth()); });

Tested 2012-03-28 on Windows 7 in latest FF, Chrome, IE & Safari and 100% working.

source: http://benalman.com/projects/jquery-misc-plugins/#scrollbarwidth

Jan Šafránek
  • 893
  • 10
  • 13
  • Returns different values with different page zoom. Win7, Opera, FF. – Kolyunya Mar 07 '13 at 09:00
  • 13
    width will ALWAYS === undefined in that code. might as well do if (true) { ... } – sstur Jul 26 '13 at 15:21
  • 3
    Correction: `width` will _always_ === undefined the **first** time the function is called. On subsequent calls to the function `width` is already set, that check just prevents the calculations being run again needlessly. – MartinAnsty Aug 01 '13 at 10:49
  • 17
    @MartinAnsty But the [width] variable is declared *inside* the function, therefore it's recreated every time you call the function. – MadSkunk Aug 14 '13 at 08:57
  • @MadSkunk you're quite right, my mistake. In that case the if statement either is doing nothing or serves some other purpose that eludes me. – MartinAnsty Aug 14 '13 at 12:56
  • 4
    @MartinAnsty, if you look at the [source](https://github.com/cowboy/jquery-misc/blob/master/jquery.ba-scrollbarwidth.js#L12), it's declared in the outer closure. – TheCloudlessSky Oct 24 '13 at 17:20
  • 3
    Just to reinforce the point made by @sstur and @TheCloudlessSky, the code above is _not_ the same as the one in Ben Alman's plugin, and it will not cache the result in `width`, but rather recalculate it every single time. It works, but it is terribly inefficient. Please do the world a favour and use the [correct version](https://github.com/cowboy/jquery-misc/blob/master/jquery.ba-scrollbarwidth.js) in Alman's plugin instead. – hashchange Nov 27 '14 at 13:51
17
window.scrollBarWidth = function() {
  document.body.style.overflow = 'hidden'; 
  var width = document.body.clientWidth;
  document.body.style.overflow = 'scroll'; 
  width -= document.body.clientWidth; 
  if(!width) width = document.body.offsetWidth - document.body.clientWidth;
  document.body.style.overflow = ''; 
  return width; 
} 
Josh Stodola
  • 81,538
  • 47
  • 180
  • 227
  • First tried the [accepted answer](http://stackoverflow.com/questions/986937/how-can-i-get-the-browsers-scrollbar-sizes#answer-986977) but found that that did no longer work in Firefox on Windows 8. Switched to this variant that does the job beautifully. – Matijs Mar 13 '14 at 09:40
  • 1
    Shorter code, but the browser has to redraw the whole page, so it is very slow. – Adrian Maire Oct 30 '14 at 16:05
9

I found a simple solution that works for elements inside of the page, instead of the page itself: $('#element')[0].offsetHeight - $('#element')[0].clientHeight

This returns the height of the x-axis scrollbar.

Memet Olsen
  • 4,578
  • 5
  • 40
  • 50
  • Great one!! You made my day :) It's working as well with ".offsetWidth" and ".clientWidth" for y-axis scrollbars. – Polosson Sep 26 '14 at 16:39
  • 1
    Doesn't seem entirely reliable, unfortunately, at least for widths. .clientWidth seems to include half the scrollbar's width in both FireFox and Chrome under Linux. – Michael Scheper Oct 24 '14 at 05:02
8

From David Walsh's blog:

// Create the measurement node
var scrollDiv = document.createElement("div");
scrollDiv.className = "scrollbar-measure";
document.body.appendChild(scrollDiv);

// Get the scrollbar width
var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth;
console.info(scrollbarWidth); // Mac:  15

// Delete the DIV 
document.body.removeChild(scrollDiv);
.scrollbar-measure {
 width: 100px;
 height: 100px;
 overflow: scroll;
 position: absolute;
 top: -9999px;
}

Gives me 17 on my website, 14 here on Stackoverflow.

mpen
  • 272,448
  • 266
  • 850
  • 1,236
5

You can determine window scroll bar with document as below using jquery + javascript:

var scrollbarWidth = ($(document).width() - window.innerWidth);
console.info("Window Scroll Bar Width=" + scrollbarWidth );
Bhuwan Prasad Upadhyay
  • 2,916
  • 1
  • 29
  • 33
5

This should do the trick, no?

function getScrollbarWidth() {
  return (window.innerWidth - document.documentElement.clientWidth);
}
Alexander
  • 396
  • 1
  • 9
  • 19
4

If you already have an element with scrollbars on it use:

function getScrollbarHeight(el) {
    return el.getBoundingClientRect().height - el.scrollHeight;
};

If there is no horzintscrollbar present the function will retun 0

mons droid
  • 1,038
  • 9
  • 10
3

The way Antiscroll.js does it in it's code is:

function scrollbarSize () {
  var div = $(
      '<div class="antiscroll-inner" style="width:50px;height:50px;overflow-y:scroll;'
    + 'position:absolute;top:-200px;left:-200px;"><div style="height:100px;width:100%"/>'
    + '</div>'
  );

  $('body').append(div);
  var w1 = $(div).innerWidth();
  var w2 = $('div', div).innerWidth();
  $(div).remove();

  return w1 - w2;
};

The code is from here: https://github.com/LearnBoost/antiscroll/blob/master/antiscroll.js#L447

Hengjie
  • 4,598
  • 2
  • 30
  • 35
3
detectScrollbarWidthHeight: function() {
    var div = document.createElement("div");
    div.style.overflow = "scroll";
    div.style.visibility = "hidden";
    div.style.position = 'absolute';
    div.style.width = '100px';
    div.style.height = '100px';
    document.body.appendChild(div);

    return {
        width: div.offsetWidth - div.clientWidth,
        height: div.offsetHeight - div.clientHeight
    };
},

Tested in Chrome, FF, IE8, IE11.

Ben
  • 54,723
  • 49
  • 178
  • 224
3

Create an empty div and make sure it's present on all pages (i.e. by putting it in the header template).

Give it this styling:

#scrollbar-helper {
    // Hide it beyond the borders of the browser
    position: absolute;
    top: -100%;

    // Make sure the scrollbar is always visible
    overflow: scroll;
}

Then simply check for the size of #scrollbar-helper with Javascript:

var scrollbarWidth = document.getElementById('scrollbar-helper').offsetWidth;
var scrollbarHeight = document.getElementById('scrollbar-helper').offsetHeight;

No need to calculate anything, as this div will always have the width and height of the scrollbar.

The only downside is that there will be an empty div in your templates.. But on the other hand, your Javascript files will be cleaner, as this only takes 1 or 2 lines of code.

That guy
  • 135
  • 2
  • 10
3
function getScrollBarWidth() {
    return window.innerWidth - document.documentElement.clientWidth;
}

Most of the browser use 15px for the scrollbar width

Shadow Grimes
  • 91
  • 1
  • 4
  • of course, this only works if the scrollbar is already visible. Sometimes we need to predict size before it is shown. Also, mobile browsers don't use 15px for scroll bar. – Garr Godfrey Aug 26 '20 at 18:52
1
function getWindowScrollBarHeight() {
    let bodyStyle = window.getComputedStyle(document.body);
    let fullHeight = document.body.scrollHeight;
    let contentsHeight = document.body.getBoundingClientRect().height;
    let marginTop = parseInt(bodyStyle.getPropertyValue('margin-top'), 10);
    let marginBottom = parseInt(bodyStyle.getPropertyValue('margin-bottom'), 10);
    return fullHeight - contentHeight - marginTop - marginBottom;
  }
allenhwkim
  • 27,270
  • 18
  • 89
  • 122
1

I've found that solution in the material-ui code and it works for me.

const scrollbarWidth = window.innerWidth -  document.querySelector('body').clientWidth;
Bogdan Surai
  • 1,197
  • 14
  • 16
0

With jquery (only tested in firefox):

function getScrollBarHeight() {
    var jTest = $('<div style="display:none;width:50px;overflow: scroll"><div style="width:100px;"><br /><br /></div></div>');
    $('body').append(jTest);
    var h = jTest.innerHeight();
    jTest.css({
        overflow: 'auto',
        width: '200px'
    });
    var h2 = jTest.innerHeight();
    return h - h2;
}

function getScrollBarWidth() {
    var jTest = $('<div style="display:none;height:50px;overflow: scroll"><div style="height:100px;"></div></div>');
    $('body').append(jTest);
    var w = jTest.innerWidth();
    jTest.css({
        overflow: 'auto',
        height: '200px'
    });
    var w2 = jTest.innerWidth();
    return w - w2;
}

But I actually like @Steve's answer better.

ling
  • 9,545
  • 4
  • 52
  • 49
0

This is a great answer: https://stackoverflow.com/a/986977/5914609

However in my case it did not work. And i spent hours searching for the solution.
Finally i've returned to above code and added !important to each style. And it worked.
I can not add comments below the original answer. So here is the fix:

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

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

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

  document.body.removeChild (outer);

  return (w1 - w2);
};
Community
  • 1
  • 1
Max Vetriakov
  • 19
  • 1
  • 5
0

This life-hack decision will give you opportunity to find browser scrollY width (vanilla JavaScript). Using this example you can get scrollY width on any element including those elements that shouldn't have to have scroll according to your current design conception,:

getComputedScrollYWidth     (el)  {

  let displayCSSValue  ; // CSS value
  let overflowYCSSValue; // CSS value

  // SAVE current original STYLES values
  {
    displayCSSValue   = el.style.display;
    overflowYCSSValue = el.style.overflowY;
  }

  // SET TEMPORALLY styles values
  {
    el.style.display   = 'block';
    el.style.overflowY = 'scroll';
  }

  // SAVE SCROLL WIDTH of the current browser.
  const scrollWidth = el.offsetWidth - el.clientWidth;

  // REPLACE temporally STYLES values by original
  {
    el.style.display   = displayCSSValue;
    el.style.overflowY = overflowYCSSValue;
  }

  return scrollWidth;
}
Evgeniy Miroshnichenko
  • 1,788
  • 2
  • 19
  • 30
0

Here's the more concise and easy to read solution based on offset width difference:

function getScrollbarWidth(): number {

  // Creating invisible container
  const outer = document.createElement('div');
  outer.style.visibility = 'hidden';
  outer.style.overflow = 'scroll'; // forcing scrollbar to appear
  outer.style.msOverflowStyle = 'scrollbar'; // needed for WinJS apps
  document.body.appendChild(outer);

  // Creating inner element and placing it in the container
  const inner = document.createElement('div');
  outer.appendChild(inner);

  // Calculating difference between container's full width and the child width
  const scrollbarWidth = (outer.offsetWidth - inner.offsetWidth);

  // Removing temporary elements from the DOM
  outer.parentNode.removeChild(outer);

  return scrollbarWidth;

}

See the JSFiddle.

Slava Fomin II
  • 26,865
  • 29
  • 124
  • 202
0

Already coded in my library so here it is:

var vScrollWidth = window.screen.width - window.document.documentElement.clientWidth;

I should mention that jQuery $(window).width() can also be used instead of window.document.documentElement.clientWidth.

It doesn't work if you open developer tools in firefox on the right but it overcomes it if the devs window is opened at bottom!

window.screen is supported quirksmode.org!

Have fun!

centurian
  • 1,168
  • 13
  • 25
0

It seems to work, but maybe there is a simpler solution that works in all browsers?

// Create the measurement node
var scrollDiv = document.createElement("div");
scrollDiv.className = "scrollbar-measure";
document.body.appendChild(scrollDiv);

// Get the scrollbar width
var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth;
console.info(scrollbarWidth); // Mac:  15

// Delete the DIV 
document.body.removeChild(scrollDiv);
.scrollbar-measure {
 width: 100px;
 height: 100px;
 overflow: scroll;
 position: absolute;
 top: -9999px;
}
Goga
  • 9
  • 5
0

I made an updated version of @Matthew Vines answer.

It's easier to read, easier to understand. It doesn't require an inner element. The element created to get the scroll bar width has a 100% height/width so it doesn't create any visible scroll bar on the body on lower end PCs/mobiles which could take a bit more time to create the element, get the widths, and finally remove the element.

const getScrollBarWidth = () => {
  const e = document.createElement('div');
  Object.assign(e.style, {
    width: '100%',
    height: '100%',
    overflow: 'scroll',
    position: 'absolute',
    visibility: 'hidden',
    top: '0',
    left: '0',
  });

  document.body.appendChild(e);

  const scrollbarWidth = e.offsetWidth - e.clientWidth;

  document.body.removeChild(e);

  return scrollbarWidth;
};

console.log(getScrollBarWidth());

I do recommend to check for the scroll bar width only once, at page load (except if it doesn't fit your needs) then store the result in a state/variable.

Anatole Lucet
  • 1,603
  • 3
  • 24
  • 43
0

You can use this solution to find the scrollbar width of any element inside the webpage rather than the webpage itself. You can also rewrite it to work for scrollbar height in the case of horizontal scrolbars by replacing its width related properties with their height related counterparts.

The offsetWidth property returns the total width of content, padding, border, and scrollbar (if there is any). Whereas, clientWidth property returns only the total width of content and padding.

So, if we substract clientWidth and horizontal border from offsetWidth, we will be left with the width of the scrollbar. That is to say, if there is any scrollbar, we will get the width of the scrollbar. But if there isn't any scrollbar, we will get 0.

const element = document.querySelector("div");
const elementStyle = window.getComputedStyle(element);
const horizontalBorder = parseFloat(elementStyle.borderLeftWidth) + parseFloat(elementStyle.borderRightWidth);
const scrollbarWidth = element.offsetWidth - element.clientWidth - horizontalBorder + "px";
arafatgazi
  • 341
  • 4
  • 5