6

I need to be able to detect whether there are scrollbars (both vertical and horizontal) on a browser window. I've been using this code but it isn't working reliably in Firefox 5.

JFL.GetScrollbarState = function () {
    var myWidth = 0;
    var myHeight = 0;
    if (document.documentElement && document.documentElement.clientWidth) {
        myWidth = document.documentElement.clientWidth;
        myHeight = document.documentElement.clientHeight;
    } else {
        myWidth = document.body.clientWidth;
        myHeight = document.body.clientHeight;
    }
    return ({
        vScrollbar: document.body.scrollHeight > myHeight,
        hScrollbar: document.body.scrollWidth > myWidth
    });
}

Is there a better way to do this that will work cross browser. My browser targets are Firefox 4-5, Chrome, Safari 4+, Opera 10+.

If you're interested in why I need to know if there are scrollbars, it's because I have some spinning CSS3 transitions that (due to the nature of their spinning) may temporarily go beyond the edges of the current document size (thus making the document temporarily larger). If were no scrollbars initially present, the CSS3 transition may cause scrollbars to show up during the transition and then go away when the transition is finished, leading to an ugly scrollbar flash. If I know that there are no scrollbars present, I can temporarily add a class that will set overflow-x or overflow-y to hidden and thus prevent the scrollbar flash during the CSS3 transition. If scrollbars are already present, I don't have to do anything because they may move a little, but they won't go on/off during the transition.

Bonus points if one can actually tell not only if scrollbars would generally be required, but whether they are actually there or not.

jfriend00
  • 683,504
  • 96
  • 985
  • 979

3 Answers3

5

After running into flicker problems with the scrolling version proposed by David in some browsers (Safari and IE), I've settled on this code that does not have the flicker problem:

function getScrollBarState() {
    var result = {vScrollbar: true, hScrollbar: true};
    try {
        var root = document.compatMode=='BackCompat'? document.body : document.documentElement;
        result.vScrollbar = root.scrollHeight > root.clientHeight;
        result.hScrollbar = root.scrollWidth > root.clientWidth;
    } catch(e) {}
    return(result);
}

It's a derivative of what I was using and the general technique was referenced in the post that fanfavorite posted. It seems to work in every browser I've tried even in IE6. For my purposes, I wanted any failure to return that there was a scrollbar so I've coded the failure condition that way.

Note: this code does not detect if a scrollbar has been forced on or off with CSS. This code detects if an auto-scrollbar is called for or not. If your page might have CSS settings that control the scrollbar, then you can get the CSS and check that first.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • I found some cases where this does not work. There are some weird layout cases in Chrome 15 where the document.documentElement is much larger than document.body causing a scrollbar and this code only looks at document.body. So, I'm back searching for a general purpose solution that works everywhere. – jfriend00 Nov 29 '11 at 23:44
  • This code does *not* detect if a scroll-bar is present. The scroll-bar may be explicitly set: `body { overflow: scroll; }` or explicitly hidden `body { overflow: hidden; }` in which case your code reports a false positive/negative... – Šime Vidas Mar 28 '12 at 19:28
  • 1
    @ŠimeVidas - This code isn't trying to detect if a scrollbar is manually set. If that's the case or is a possibility in your case, then just get the CSS and check that first. This code is trying to detect if there's a size trigger for an auto scrollbar or not. If you have a better way, please feel free to post that. – jfriend00 Mar 28 '12 at 21:19
  • I have found that a vertical scroll-bar can be detected by evaluating the expression `window.innerWidth - document.documentElement.clientWidth` - if the scroll-bar is present, the value will be `17`, otherwise it will be `0`. However, `window.innerWidth` is not implemented in IE7/8, and there seems to be no way to retrieve at all that value in those two browsers... `:(` – Šime Vidas Mar 29 '12 at 00:56
  • @ŠimeVidas - if you explicitly set the scrollbar to be always on in your CSS, then your javascript detection of if the scrollbar is on is ever simpler: `if (true){ /* of course it's on...you set it that way! */ }` :) – Jimbo Jonny Oct 15 '12 at 18:58
2

Have you taken a look at this other post? How can I detect a Scrollbar presence ( using Javascript ) in HTML iFrame?

Community
  • 1
  • 1
fanfavorite
  • 5,128
  • 1
  • 31
  • 58
1

It's actually pretty easy. This will work in every modern browser:

// try scrolling by 1 both vertically and horizontally
window.scrollTo(1,1);

// did we move vertically?
if (window.pageYOffset != 0) {
 console.log("houston, we have vertical scrollbars");
}

// did we move horizontally?
if (window.pageXOffset != 0) {
 console.log("houston, we have horizontal scrollbars");
}

// reset window to default scroll state
window.scrollTo(0,0);
David Titarenco
  • 32,662
  • 13
  • 66
  • 111
  • Nice! I had to adapt it in case the window was already scrolled some to preserve the current scroll position and scroll one pixel from that. I know I didn't ask for something that works in IE, but for other people reading, this works in IE9 and does not work in IE6 (I didn't try IE7 and IE8). – jfriend00 Jul 07 '11 at 18:16
  • jsFiddle that I used to test it in various places: http://jsfiddle.net/jfriend00/4NhUQ/ – jfriend00 Jul 07 '11 at 18:17
  • 1
    FYI, I was looking into how to make this work in all browsers (just out of completeness), but it turns out this technique won't ever work in IE6 because IE6 will scroll the document with scrollTo or scrollBy even if there are no scroll bars so this technique always thinks there are scrollbars in IE6. – jfriend00 Jul 07 '11 at 19:20
  • Yep, this technique won't work in any IE older than v9. I don't think it's possible to actually do it in older versions if IE altogether. – David Titarenco Jul 07 '11 at 19:22
  • So, it turns out that this technique has a problem in Safari. The succession of window.scrollTo(1,1) and window.scrollTo(0,0) causes the window to actually move in Safari. I detect no movement in the other browsers, but it does move in Safari. That is a problem as I don't want the window contents to shake every time I inquire if there's a scrollbar. I'm back to ground zero looking for a good technique. Crap. I'd like to unset the accepted answer, but SO won't let me. – jfriend00 Jul 10 '11 at 04:59
  • This technique also has a problem if the window is not scrolled to the top. – jfriend00 Jul 10 '11 at 05:26