Detect Scrollbar Width with JavaScript

By  on  

I've recently been working on an advanced JavaScript-based grid solution and let me tell you: it's quite an undertaking. Making sure the grid is accessible, reactive, efficient, and cross-browser compatible is difficult, but even the minor workings of each of those are hard. One small task was detecting the width of the vertical scrollbar so that I know how wide the grid body truly was. Here's the tiny snippet to do it:

The CSS

The element we create for measurement will need to be positioned off screen so the user doesn't notice it:

/* way the hell off screen */
.scrollbar-measure {
	width: 100px;
	height: 100px;
	overflow: scroll;
	position: absolute;
	top: -9999px;
}

You could add these styles directly to the element, but they'd bloat the JavaScript portion a bit.

The JavaScript

The obvious parts is creating a DIV to inject into the DOM and adding the CSS class we created above:

// 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.warn(scrollbarWidth); // Mac:  15

// Delete the DIV 
document.body.removeChild(scrollDiv);

With the element in the page, subtracting the clientWidth from the offsetWidth gives the scrollbar size! The last step is removing the DIV from the DOM and done!

Since the scrollbar size is different between Mac and Windows (and even Internet Explorer 7 vs. other IE versions), this small but dynamic snippet is just what I needed to find the true content area of the container. Feel free to convert this JavaScript snippet into whatever JavaScript framework your prefer!

Recent Features

  • By
    LightFace:  Facebook Lightbox for MooTools

    One of the web components I've always loved has been Facebook's modal dialog.  This "lightbox" isn't like others:  no dark overlay, no obnoxious animating to size, and it doesn't try to do "too much."  With Facebook's dialog in mind, I've created LightFace:  a Facebook lightbox...

  • By
    7 Essential JavaScript Functions

    I remember the early days of JavaScript where you needed a simple function for just about everything because the browser vendors implemented features differently, and not just edge features, basic features, like addEventListener and attachEvent.  Times have changed but there are still a few functions each developer should...

Incredible Demos

  • By
    Create Your Own Dijit CSS Theme with LESS CSS

    The Dojo Toolkit seems to just get better and better.  One of the new additions in Dojo 1.6 was the use of LESS CSS to create Dijit themes.  The move to using LESS is a brilliant one because it makes creating your own Dijit theme...

  • By
    WebSocket and Socket.IO

    My favorite web technology is quickly becoming the WebSocket API. WebSocket provides a welcomed alternative to the AJAX technologies we've been making use of over the past few years. This new API provides a method to push messages from client to server efficiently...

Discussion

  1. Handy! I’ve done something similar to an individual element but didn’t think to abstract it like you did.

    Fun thing: if you give a scrollable element a negative right-margin of the scrollbar width and a parent with its overflow hidden, you can have a mousewheel-scrollable element that looks overflow-hidden, Kinda esoteric, but useful if you’re trying to make a UI w/o any browser chrome.

  2. Graeme Coultrip

    Have you tried this on Safari on OS X Lion?

    • OS X Lion (but not earlier versions) floats scrollbars on top of the content. As a result there is no resize when a scrollbar appears. Which means this method of measuring scrollbar width does not work in Lion.

      I’m not aware of any method of getting the scrollbar width in Lion. :(

  3. swhiteman

    @Tommy: I do this with a all over the “control panel” area of our site. I don’t use a wrapper element, though, I use CSS clip to remove the scrollbar.

    I think it creates a really useful widget — obviously not as beautiful as you can create from scratch, but for basic form use it looks nice and “flat” and, as you note, is mousewheel/two-finger scrollable and retains other native behaviors (ctrl-click, etc.) without having to rewrite them.

  4. swhiteman

    Hmm, I deliberately didn’t wrap a tag hoping it would stay inline, shmoops.

    What I was saying is that, along similar lines, I like to clip: a multi-select to remove the scrollbar. Creates a very useful widget which retains native behaviors (mousewheel/two-finger, ctrl-click to select) while still fitting nicely into a flat design.

  5. Interesting. You can read some other interesting JavaScript tips and things at my blog: http://joezimjs.com
    It’s new and needs some more content, but it’s on its way.

  6. towry

    I don’t know why,It always show document.body is null in my firebug console.

  7. Daniel

    Hey man, I’m using Chrome and this line doesn’t work on my browser: “document.body.appendChild(scrollDiv);”

    I get this error in the web inspector console: “Uncaught TypeError: Cannot call method ‘appendChild’ of null”

    • You’ll want to put that in a domReady block, or at the bottom of the page.

  8. That’s brilliant, thanks very much.

    I’ve had some alignment issues caused with Lion’s hidden scrollbars and so now I use this to detect if the scrollbars are shown and then add a padding class to the affected divs ala

          if (scrollbarWidth > 0) {
            $(".trpChatContainer").addClass("scrollchat");
            $(".trpChatInputArea").addClass("scrollpush");
          }
    

    I then also style the scrollbar if it’s visible so that it looks more elegant:

    /* Track */
    .scrollchat::-webkit-scrollbar-track {
    /*    -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3); */
    }
     
    /* Handle */
    .scrollchat::-webkit-scrollbar-thumb {
        -webkit-border-radius: 10px;
        border-radius: 10px;
        background: rgba(0,0,0,0.2);
        margin-right: 1px;
        .transition300ms;
    }
    .scrollchat:hover::-webkit-scrollbar-thumb {
        -webkit-border-radius: 10px;
        border-radius: 10px;
        background: rgba(0,0,0,0.4);
        margin-right: 1px;
        .transition300ms;
    }
    .scrollchat::-webkit-scrollbar-thumb:window-inactive {
      background: rgba(0,0,0,0.1); 
    }
    
  9. Hey David, thnx you saved the day :-) A simple and elegant solution for a common problem. I’m using the script in combination with jQuery to correct a centered div maximage background script:

    $('.container').css('padding-left', scrollbarWidth); 
    
  10. Sakthi

    Thanks. Its working fine in IE

  11. Hi David, thank you for this post!
    Unfortunately I get a value of 0 in both Chrome and Firefox. Any idea why it isn’t working?

    • On Mac? Possibly because the scrollbar is technically over the content :/

    • neil

      This is the #1 constraint that everybody seems to overlook.
      The general idea of using scrollWidth-clientWidth (or some such variant) to calculate the width of a vertical scroll overlooks two obvious factors:
      1. What Dave Walsh mentions – which is that browsers like Firefox and Torch overlay the scrollbar on the content.
      2. That the scrollbar width is customisable independently of the content width. The CSS scrollbar-width property wouldn’t work otherwise.

      If you’re looking for the scrollbar width on something other than the root container (e.g. a div) then the width-difference approach might work. But generally it fails for the document as a whole.

  12. Oh, you beautiful genius. This is lovely.

  13. sanbor

    How about this:

    var scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
    
  14. Renzo

    I think the trick is to measure a div inside a div with scrollbar. Here’s a CodePen: http://codepen.io/parziphal/pen/qrZGLw

  15. Denis

    Posted code does not work on my mac. this one works
    https://stackoverflow.com/a/13382873/1221082

Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!