134

I just want some simple JQ/JS to check if the current page/window (not a particular element) has a vertical scrollbar.

Googling gives me stuff that seems overly complex for just this basic feature.

How can this be done?

Woody
  • 1,341
  • 2
  • 9
  • 4

13 Answers13

104
$(document).ready(function() {
    // Check if body height is higher than window height :)
    if ($("body").height() > $(window).height()) {
        alert("Vertical Scrollbar! D:");
    }

    // Check if body width is higher than window width :)
    if ($("body").width() > $(window).width()) {
        alert("Horizontal Scrollbar! D:<");
    }
});
danday74
  • 52,471
  • 49
  • 232
  • 283
Thiago Belem
  • 7,732
  • 5
  • 43
  • 64
  • 15
    +1 but for the sake of exactness, this only checks whether the content expands further than the viewport. If the `overflow` property of the `body` is set to `hidden` somewhere along the line, it won't work. Setting hidden on a body is extremely rare, though. – Pekka Jan 27 '10 at 12:57
  • 5
    This does not work if the body height matches the window height, which is the case if the doc height matches the viewport exactly *then a horizontal scrollbar is added*. It will force vert. scrollbar but doc/body/window height are the same; it will NOT alert "vertical scrollbar" even tho there is one. – Stop Slandering Monica Cellio Nov 27 '12 at 21:55
  • 2
    Just thought I'd mention that I had to use `$(document)` instead of `$("body")`, this worked for me when body didn't (I have an absolute positoned container with an aspect ratio on width/height) – am_ Jun 12 '14 at 12:26
  • 1
    I have report page on Chrome browser where it initially displays a scroll bar and vanishes in a matter of milliseconds which looks like a browser behaviour since I did not programme it. So this function return true always in my case.. – D777Stack Jun 24 '15 at 08:02
  • @TiuTalk for me $("body").height() & $(window).height() gives same value, instead I use $(document).height() > $(window).height() it works for me. – SarangK Oct 04 '16 at 05:08
89

try this:

var hasVScroll = document.body.scrollHeight > document.body.clientHeight;

This will only tell you if the vertical scrollHeight is bigger than the height of the viewable content, however. The hasVScroll variable will contain true or false.

If you need to do a more thorough check, add the following to the code above:

// Get the computed style of the body element
var cStyle = document.body.currentStyle||window.getComputedStyle(document.body, "");

// Check the overflow and overflowY properties for "auto" and "visible" values
hasVScroll = cStyle.overflow == "visible" 
             || cStyle.overflowY == "visible"
             || (hasVScroll && cStyle.overflow == "auto")
             || (hasVScroll && cStyle.overflowY == "auto");
Andy E
  • 338,112
  • 86
  • 474
  • 445
  • 1
    +1 Nice! And with the necessary computed style (which was the point at which I decided not to get involved with this question ;) – Pekka Jan 27 '10 at 13:04
  • lol yeah I was debating whether or not to make the extra effort to write it because in many cases it's not needed. – Andy E Jan 27 '10 at 13:08
  • Yeah, but it's the only really proper way. Good job! – Pekka Jan 27 '10 at 13:12
  • I found a page layout where this technique does not work. For some odd reason, document.body is smaller than the window, but document.documentElement is not so the code in this test says no vscrollbar, but there is one. – jfriend00 Nov 29 '11 at 23:56
  • It didn't work for me in the internet explorer, while the one of TiuTalk does. – devsnd Apr 26 '12 at 16:11
  • Are you missing a var keyword before hasVScroll or is that intentionally global? I see it's checking the value of hasVScroll in the condition, before it's assigned, so it seems like it's maintaining state from a previous check. – Triynko Dec 11 '15 at 21:26
  • 1
    This results in hasVScroll being true whenever overflowY is 'visible' regardless of whether the scrollHeight is greater than the clientHeight. Maybe you meant `cStyle.overflow === 'scroll'`? – B T Oct 03 '16 at 21:11
  • 7
    The above code does not work. Browser: Chrome 56. Url: https://news.greylock.com/the-hierarchy-of-engagement-expanded-648329d60804#.w3zl8fs6p – Sebastien Lorber Mar 16 '17 at 09:38
  • 1
    @BT `cStyle.overflow == "visible" ` can show scroll bars when the element is the `document.body`. But it should be (hasVScroll && cStyle.overflow == "visible" && element.nodeName == "BODY") . Plus it needs to check for `cStyle.overflow === 'scroll'` as you point out. – mseifert Apr 02 '17 at 07:22
48

I tried the previous answer and doesn't seem to be working the $("body").height() does not necessarily represent the whole html height.

I have corrected the solution as follows:

// Check if body height is higher than window height :) 
if ($(document).height() > $(window).height()) { 
    alert("Vertical Scrollbar! D:"); 
} 

// Check if body width is higher than window width :) 
if ($(document).width() > $(window).width()) { 
    alert("Horizontal Scrollbar! D:<"); 
} 
1man
  • 5,216
  • 7
  • 42
  • 56
Bharat
  • 3,491
  • 1
  • 22
  • 22
18

Let's bring this question back from the dead ;) There is a reason Google doesn't give you a simple solution. Special cases and browser quirks affect the calculation, and it is not as trivial as it seems to be.

Unfortunately, there are problems with the solutions outlined here so far. I don't mean to disparage them at all - they are great starting points and touch on all the key properties needed for a more robust approach. But I wouldn't recommend copying and pasting the code from any of the other answers because

  • they don't capture the effect of positioned content in a way that is reliable cross-browser. The answers which are based on body size miss this entirely (the body is not the offset parent of such content unless it is positioned itself). And those answers checking $( document ).width() and .height() fall prey to jQuery's buggy detection of document size.
  • Relying on window.innerWidth, if the browser supports it, makes your code fail to detect scroll bars in mobile browsers, where the width of the scroll bar is generally 0. They are just shown temporarily as an overlay and don't take up space in the document. Zooming on mobile also becomes a problem that way (long story).
  • The detection can be thrown off when people explicitly set the overflow of both the html and body element to non-default values (what happens then is a little involved - see this description).
  • In most answers, body padding, borders or margins are not detected and distort the results.

I have spent more time than I would have imagined on a finding a solution that "just works" (cough). The algorithm I have come up with is now part of a plugin, jQuery.isInView, which exposes a .hasScrollbar method. Have a look at the source if you wish.

In a scenario where you are in full control of the page and don't have to deal with unknown CSS, using a plugin may be overkill - after all, you know which edge cases apply, and which don't. However, if you need reliable results in an unknown environment, then I don't think the solutions outlined here will be enough. You are better off using a well-tested plugin - mine or anybody elses.

Community
  • 1
  • 1
hashchange
  • 7,029
  • 1
  • 45
  • 41
  • Thanks. Quite a bit complicated! If you don't want to/need to be backward compatible is there perhaps an easier solution for html5 browsers? I mean perhaps the browser coders/w3c have been nice enough to just tell us if there are scrollbars or not on an element? ;-) – Leo Apr 11 '15 at 01:36
  • 1
    @Leo Not that I am aware of. Well, there is a [`window.scrollbars` object](https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollbars) which has a single property, `visible`. Sounds promising but isn't. It is not supported in IE, including IE11. And it just tells you that there is _a_ scroll bar - but not which one. See the [test page here](http://jsbin.com/bofofo). – hashchange Apr 17 '15 at 16:51
  • Thanks @hashchange. It sounds incredible stupid that it just tells if there is any scrollbar so I guess it is just some kind of test yet. A bit promising though. ;-) – Leo Apr 17 '15 at 23:39
  • Would you mind commenting on Andy E's answer? It seems like that one doesn't fall prey to any of the 4 points you brought up, but it sounds like you've done a ton more work on this than anyone else, so I'm curious where it would go wrong. – B T Oct 03 '16 at 23:35
  • @BT Maybe I'm a bit dense this morning, but how do you get that code to detect that there is _no_ scrollbar? With default overflow settings, it always evaluates to true. – hashchange Oct 04 '16 at 09:03
  • @hashchange Here's the function I derived from Andy E's answer that I'm using: http://codepen.io/anon/pen/vXpBVb – B T Oct 05 '16 at 01:19
  • 1
    @BT Ok, great. Now let me lead you to the entrance of the rabbit hole ;) Here's [a demo](http://jsbin.com/tayurek/2/edit?html,js,output) where the content is not enough to fill the window. Your detection works in FF but fails in Chrome. And here's [another demo](http://jsbin.com/hoviri/2/edit?html,css,js,output) where a positioned element is placed far down the page. Your detection works in Chrome but fails in FF. – hashchange Oct 05 '16 at 10:00
  • 1
    @BT And I guess we can get into a bunch of weird failure modes when we begin to play with overflow settings because their [behaviour is a little odd](http://stackoverflow.com/questions/12434416/overflowhidden-on-body-is-broken-in-ios6/28673415#28673415), but I've stopped right there. – hashchange Oct 05 '16 at 10:01
  • Alright then fair enough. I suppose I've only used my function on things that aren't the document body. I see your function is hard coded for the window. This is some complicated junk that should just be a native built in function – B T Oct 05 '16 at 10:11
  • I see that your code has written a couple things that I've written as dom utilties, including finding scrollbar width and css finding. I'm planning on creating a dom utility module (on github and npm) to put some of this difficult-to-write code, and I'm wondering if you'd want to help me do that. – B T Oct 05 '16 at 23:17
  • @BT Sounds like an interesting idea. But doesn't a library of that sort, of decent quality, already exist? Anyway, I'm not in because I'm running 10 open source projects already, and I'm struggling to keep up. But if you'd like to share a link, I'd be happy to have a look. – hashchange Oct 07 '16 at 19:22
  • If it did, wouldn't we both be using it? Or wouldn't it have appeared on this SO question? I'll add a link here when I get around to putting it up. – B T Oct 07 '16 at 20:17
16

This one did works for me:

function hasVerticalScroll(node){
    if(node == undefined){
        if(window.innerHeight){
            return document.body.offsetHeight> window.innerHeight;
        }
        else {
            return  document.documentElement.scrollHeight > 
                document.documentElement.offsetHeight ||
                document.body.scrollHeight>document.body.offsetHeight;
        }
    }
    else {
        return node.scrollHeight> node.offsetHeight;
    }
}

For the body, just use hasVerticalScroll().

agm1984
  • 15,500
  • 6
  • 89
  • 113
Kees C. Bakker
  • 32,294
  • 27
  • 115
  • 203
16
let hasScrollbar = window.innerWidth > document.documentElement.clientWidth;
Roman Zaykovsky
  • 493
  • 5
  • 12
3

Oddly none of these solutions tell you if a page has a vertical scrollbar.

window.innerWidth - document.body.clientWidth will give you the width of the scrollbar. This should work in anything IE9+ (not tested in the lesser browsers). (Or to strictly answer the question, !!(window.innerWidth - document.body.clientWidth)

Why? Let's say you have a page where the content is taller than the window height and the user can scroll up/down. If you're using Chrome on a Mac with no mouse plugged in, the user will not see a scrollbar. Plug a mouse in and a scrollbar will appear. (Note this behaviour can be overridden, but that's the default AFAIK).

David Gilbertson
  • 4,219
  • 1
  • 26
  • 32
  • The explanation of Chrome-Mouse behaviour helped me figure out what I thought was inconsistent behaviour. Thanks! – theisof Dec 07 '17 at 10:30
3
    <script>
    var scrollHeight = document.body.scrollHeight;
    var clientHeight = document.documentElement.clientHeight;
    var hasVerticalScrollbar = scrollHeight > clientHeight;

    alert(scrollHeight + " and " + clientHeight); //for checking / debugging.
    alert("hasVerticalScrollbar is " + hasVerticalScrollbar + "."); //for checking / debugging.
    </script>

This one will tell you if you have a scrollbar or not. I've included some information that may help with debugging, which will display as a JavaScript alert.

Put this in a script tag, after the closing body tag.

Don D.
  • 31
  • 2
2

I found vanila solution

var hasScrollbar = function() {
  // The Modern solution
  if (typeof window.innerWidth === 'number')
    return window.innerWidth > document.documentElement.clientWidth

  // rootElem for quirksmode
  var rootElem = document.documentElement || document.body

  // Check overflow style property on body for fauxscrollbars
  var overflowStyle

  if (typeof rootElem.currentStyle !== 'undefined')
    overflowStyle = rootElem.currentStyle.overflow

  overflowStyle = overflowStyle || window.getComputedStyle(rootElem, '').overflow

    // Also need to check the Y axis overflow
  var overflowYStyle

  if (typeof rootElem.currentStyle !== 'undefined')
    overflowYStyle = rootElem.currentStyle.overflowY

  overflowYStyle = overflowYStyle || window.getComputedStyle(rootElem, '').overflowY

  var contentOverflows = rootElem.scrollHeight > rootElem.clientHeight
  var overflowShown    = /^(visible|auto)$/.test(overflowStyle) || /^(visible|auto)$/.test(overflowYStyle)
  var alwaysShowScroll = overflowStyle === 'scroll' || overflowYStyle === 'scroll'

  return (contentOverflows && overflowShown) || (alwaysShowScroll)
}
Sergii Shvager
  • 1,226
  • 9
  • 14
  • 1
    Not working in IE 11. window.innerWidth & document.documentElement.clientWidth are always same. – NLV Mar 29 '16 at 15:27
  • Fixed it. This same function works for IE 11 too. The issue was this - http://stackoverflow.com/questions/17045132/scrollbar-overlay-in-ie10-how-do-you-stop-that – NLV Mar 29 '16 at 15:49
  • I tested this in Chrome 65 and it works. But when I adapt it for horizontal scrollbars, the result is strange: If both horizontal and vertical scrollbar are displayed, `window.innerWidth > document.documentElement.clientWidth` is true, but `window.innerHeight > document.documentElement.clientHeight` is not. It looks as if it were the other way around in this case. I am not a JS developer, I just need it for Selenium tests. I am grateful for hints. – kriegaex Mar 25 '18 at 04:35
2

I use

function windowHasScroll()
{
    return document.body.clientHeight > document.documentElement.clientHeight;
}
amoss
  • 1,571
  • 1
  • 15
  • 27
  • this works fine but if you add height to body `height: 100%` then this will NOT work. – Syed Jun 04 '21 at 04:07
1

Simply compare the width of the documents root element (i.e. html element) against the inner portion of the window:

if ((window.innerWidth - document.documentElement.clientWidth) >0) console.log('V-scrollbar active')

If you also need to know the scrollbar width:

vScrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
Babak
  • 19
  • 2
  • this is a clever solution and handles a edge case where html element has `overflow-y: scroll` but there is no actual overflow on the page. other solutions that check the height for overflow fails this edge case. – kimbaudi Apr 23 '21 at 23:43
0

Other solutions didn't work in one of my projects and I've ending up checking overflow css property

function haveScrollbar() {
    var style = window.getComputedStyle(document.body);
    return style["overflow-y"] != "hidden";
}

but it will only work if scrollbar appear disappear by changing the prop it will not work if the content is equal or smaller than the window.

jcubic
  • 61,973
  • 54
  • 229
  • 402
0

I wrote an updated version of Kees C. Bakker's answer:

const hasVerticalScroll = (node) => {
  if (!node) {
    if (window.innerHeight) {
      return document.body.offsetHeight > window.innerHeight
    }
    return (document.documentElement.scrollHeight > document.documentElement.offsetHeight)
      || (document.body.scrollHeight > document.body.offsetHeight)
  }
  return node.scrollHeight > node.offsetHeight
}

if (hasVerticalScroll(document.querySelector('body'))) {
  this.props.handleDisableDownScrollerButton()
}

The function returns true or false depending whether the page has a vertical scrollbar or not.

For example:

const hasVScroll = hasVerticalScroll(document.querySelector('body'))

if (hasVScroll) {
  console.log('HAS SCROLL', hasVScroll)
}
agm1984
  • 15,500
  • 6
  • 89
  • 113
  • this does not work if you explicitly set `overflow-y: scroll` on html tag and the page does not contain overflow. in this case, the vertical scrollbar will be visible (even though there is no overflow) and `hasVerticalScroll(document.querySelector('body'))` would incorrectly return `false`. @Babak's solution will handle this case. – kimbaudi Apr 23 '21 at 23:37