129

The following HTML will display a scroll bar on the right inside edge of div.container.

Is it possible to determine the width of that scroll bar?

<div class="container" style="overflow-y:auto; height:40px;">
  <div class="somethingBig"></div>
</div>
user1032531
  • 24,028
  • 57
  • 174
  • 325
  • 1
    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 – JoostS May 19 '16 at 19:00

9 Answers9

265

This function should give you width of scrollbar

function getScrollbarWidth() {

  // 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;

}

Basic steps here are:

  1. Create hidden div (outer) and get it's offset width
  2. Force scroll bars to appear in div (outer) using CSS overflow property
  3. Create new div (inner) and append to outer, set its width to '100%' and get offset width
  4. Calculate scrollbar width based on gathered offsets

Working example here: http://jsfiddle.net/slavafomin/tsrmgcu9/

Update

If you're using this on a Windows (metro) App, make sure you set the -ms-overflow-style property of the 'outer' div to scrollbar, otherwise the width will not be correctly detected. (code updated)

Update #2 This will not work on Mac OS with the default "Only show scrollbars when scrolling" setting (Yosemite and up).

Slava Fomin II
  • 21,036
  • 19
  • 98
  • 176
lostsource
  • 18,908
  • 9
  • 61
  • 86
  • That is such an awesome solution. Thank you. – digitalextremist Dec 09 '13 at 13:22
  • Nice. You can make it even better if you use a closure attached to the function to cache the value and return it so that the function only needs to create/destroy the divs and calculate the value once. – Sildoreth Jan 21 '14 at 22:59
  • Unfortunately this didn't work for me in IE7 (which I need to support). – WynandB Mar 17 '14 at 00:18
  • If you have a error: `Uncaught TypeError: Cannot read property 'appendChild' of null` This could be fixed with next code line: `if (document.body == null) return 0;` before `document.body.appendChild(outer);` – Andriyun Dec 02 '14 at 10:04
  • @Andriyun I guess you would get that error if you execute the function before the document is has loaded (`window.onload`) – lostsource Dec 02 '14 at 11:48
  • Yep! Sometimes it will would be need, in other process on page. – Andriyun Dec 02 '14 at 12:11
  • Is there a way to calculate this value for the `body`'s scrollbar? – Konstantin Tarkus Jan 22 '15 at 16:38
  • @KonstantinTarkus What browser are you using? Shouldn't the body scrollbar design be the same as the rest of scrollbars appearing in overflowing divs? – lostsource Jan 22 '15 at 16:42
  • @lostsource, this solution doesn't work in Mac OS Chrome and Mac OS Safari – iKBAHT Nov 26 '15 at 15:24
  • i wish they standardize this, this is a whole lot of functionality to be performed, for some issue i need it, like mousemove, and changeable content. – deadManN Oct 17 '16 at 08:03
  • Great Job...!!! – Sodhi saab Nov 25 '16 at 14:08
  • Nice, very nice, you are Genius – AmerllicA Sep 23 '17 at 06:48
  • Some shorter... https://jsfiddle.net/suy7o8rh/ (because you don't need to hide and remove the elements) – Froschkoenig84 Jan 16 '18 at 18:10
  • Not working in Chrome on Chromebook – Dylan Maxey Dec 08 '19 at 09:56
  • Great solution. Thanks for sharing. Please note that if, for some reason, outer/inner div inherits a padding or border css style, the function returns a wrong result. Therefore, I recommend adding `outer.style.padding = '0'; outer.style.border = 'none'` and `inner.style.padding = '0'; inner.style.border = 'none'` in the function. – xfra35 Apr 06 '20 at 15:21
  • For me it was producing inconsistent result because either horisontal or vertical scrollbar was applied to the outer element. I fixed it like this: `const scrollbarWidth = outer.offsetWidth > 0 ? outer.offsetWidth - inner.offsetWidth : outer.offsetHeight - inner.offsetHeight;`. – Andrey Mikhaylov - lolmaus Mar 08 '21 at 15:03
48

// offsetWidth includes width of scroll bar and clientWidth doesn't. As rule, it equals 14-18px. so:

 var scrollBarWidth = element.offsetWidth - element.clientWidth;
Vasyl Gutnyk
  • 4,153
  • 2
  • 29
  • 35
  • 3
    offsetWidth doesn't include scrollbar, at least in the current latest chrome – David Guan Dec 29 '17 at 01:49
  • @DavidGuan ok, i will check it – Vasyl Gutnyk Dec 29 '17 at 06:52
  • 2
    I tested this solution on Chrome 64 & FireFox 58, on Windows 10 and this works and by far the cleanest solution, in my opinion. I imagine @DavidGuan must be running on Mac OS X? In that case, scrollbars is an overlay and doesn't actually effect the geometry of the DOM, so I'd expect offsetWidth and clientWidth will always be equal on Macs, unless if you're using a non-mac mouse. – Norman Breau Mar 12 '18 at 14:41
  • 2
    document.body.offsetWidth doesn't include the scrollbar but myElement.offsetWidth does as long as it isn't the body. – Curtis Jul 15 '18 at 08:01
  • should include code for how you got to `element` – Julix May 13 '19 at 23:37
  • @Julix For example: document.getElementById("testElement").U can do it in different ways. – Vasyl Gutnyk May 14 '19 at 12:43
  • I didn't mean that I mean like a context. Which element is important and why? Can you just use `window`? – Julix May 17 '19 at 20:18
  • I also agree that this is by far the cleanest solution. One thing to add is that the `offsetWidth` also includes `margin` and `border` widths so if those values are set they need to be subtracted as well. – niiyeboah Dec 04 '19 at 11:56
  • The accepted answer is ok if all you want to know is what the width of the scrollbar will be *if* it is displayed, but I needed something to check what the scrollbar's width was at any time (i.e. if displayed or not) and using an arbitrary element got me on the right path. In react I can pass a ref to *any* DOMNode and get the width value I need. – Drew Reese Sep 17 '20 at 22:30
21

I think this will be simple and fast -

var scrollWidth= window.innerWidth-$(document).width()
Ujjwal Kumar Gupta
  • 1,665
  • 1
  • 14
  • 29
  • 6
    I was using this, not sure why you'd need to insert a DIV `const scrollbarWidth = window.innerWidth - document.body.offsetWidth` – Scott Leonard Jan 22 '20 at 21:09
  • 1
    @Scott Leonard This does not work if you have `overflow:hidden` on html and body. Inserting the `
    ` is to be sure to have an element with a scrollbar.
    – Esger Sep 21 '20 at 07:04
13

If the child takes the full width of the container excluding scrollbar (the default), then you can subtract the widths:

var child = document.querySelector(".somethingBig");
var scrollbarWidth = child.parentNode.offsetWidth - child.offsetWidth;
pimvdb
  • 141,012
  • 68
  • 291
  • 345
7

If you use jquery.ui, try this code:

$.position.scrollbarWidth()
ashleedawg
  • 17,207
  • 5
  • 53
  • 80
Alvego
  • 278
  • 3
  • 6
  • Note to other jQuery newb's: This requires both jQuery and jQuery.UI (however it does return the scrollbar width, while the other methods above don't work in Firefox for me.) eg, ` ` – ashleedawg May 15 '19 at 08:40
4

Here's an easy way using jQuery.

var scrollbarWidth = jQuery('div.withScrollBar').get(0).scrollWidth - jQuery('div.withScrollBar').width();

Basically we subtract the scrollable width from the overall width and that should provide the scrollbar's width. Of course, you'd want to cache the jQuery('div.withScrollBar') selection so you're not doing that part twice.

Timothy Beamish
  • 264
  • 2
  • 9
4

Assuming container is only on page once and you are using jQuery, then:

var containerEl = $('.container')[0];
var scrollbarWidth = containerEl.offsetWidth - containerEl.clientWidth;

Also see this answer for more details.

Community
  • 1
  • 1
robocat
  • 4,857
  • 40
  • 62
3

I've used next function to get scrollbar height/width:

function getBrowserScrollSize(){

    var css = {
        "border":  "none",
        "height":  "200px",
        "margin":  "0",
        "padding": "0",
        "width":   "200px"
    };

    var inner = $("<div>").css($.extend({}, css));
    var outer = $("<div>").css($.extend({
        "left":       "-1000px",
        "overflow":   "scroll",
        "position":   "absolute",
        "top":        "-1000px"
    }, css)).append(inner).appendTo("body")
    .scrollLeft(1000)
    .scrollTop(1000);

    var scrollSize = {
        "height": (outer.offset().top - inner.offset().top) || 0,
        "width": (outer.offset().left - inner.offset().left) || 0
    };

    outer.remove();
    return scrollSize;
}

This jQuery-based solutions works in IE7+ and all other modern browsers (including mobile devices where scrollbar height/width will be 0).

Gromo
  • 1,579
  • 1
  • 12
  • 14
0

this worked for me..

 function getScrollbarWidth() { 
    var div = $('<div style="width:50px;height:50px;overflow:hidden;position:absolute;top:-200px;left:-200px;"><div style="height:100px;"></div>'); 
    $('body').append(div); 
    var w1 = $('div', div).innerWidth(); 
    div.css('overflow-y', 'scroll'); 
    var w2 = $('div', div).innerWidth(); 
    $(div).remove(); 
    return (w1 - w2); 
}
  • 1
    Looks much like http://jdsharp.us/jQuery/minute/calculate-scrollbar-width.php but you did not credit the original source, bad form! – Darryl Miles Sep 04 '15 at 00:46
  • 1
    @DarrylMiles here you go.. i don't want to take credit and never thought of that, just wanted to post ans which worked for me and didn't find same in this post. – Narendra Kothule Sep 09 '15 at 04:36