Reputation: 105091
What's the fastest way of checking whether an element has scroll bars?
One thing of course is checking whether element is larger than its viewport, which can easily be done by checking these two values:
el.scrollHeight > el.offsetHeight || el.scrollWidth > el.offsetWidth
but that doesn't mean that it has scrollbars as well (so it can actually be scrolled by humans).
How do I check for scrollbars in a 1 cross browser and 2 javascript only (as in no jQuery) way?
Javascript only, because I need as small overhead as possible, because I'd like to write a very fast jQuery selector filter
// check for specific scrollbars
$(":scrollable(x/y/both)")
// check for ANY scrollbar
$(":scrollable")
I suppose I'd have to check for overflow
style settings but how do I do that in a cross browser way?
Not only overflow
style settings. Checking whether an element has a scrollbar isn't as trivial as it seems. The first formula I've written above works fine when element doesn't have a border, but when it does (especially when border is of considerable width), offset
dimension can be larger than scroll
dimension but the element can still be scrollable. We actually have to subtract borders from offset
dimension to get the actual scrollable viewport of the element and compare that to scroll
dimension.
:scrollable
jQuery selector filter is included in my .scrollintoview()
jQuery plugin. Complete code can be found in my blog post if anybody needs it. Even though it didn't provide the actual solution Soumya's code considerably helped me solve the problem. It pointed me in the right direction.
Upvotes: 161
Views: 155359
Reputation: 130810
animation-timeline
allows to infer a scrollable element and style it accordingly:
article {
/* base demo styles: */
height: 100px;
width: 300px;
border: 4px solid red;
overflow: auto;
resize: vertical;
/* the trick (and @keyframes below): */
animation: scroll-shadows;
animation-timeline: scroll(self);
animation-range: 0 100%;
}
/* simulate content */
article::before{
content: 'Resize me';
display: block;
height: 150px;
}
@keyframes scroll-shadows {
from, to { border-color: green; }
}
<article></article>
👉 See support table (spoilers - no Firefox)
while this answer might not be helpful to most now, it will certainly become more and more relevant as time passes and support grows.
Also, for us who are lucky enough to work on Chrome-only products, this can be used right now.
Upvotes: 1
Reputation: 47
Most likely for the horizontal scrollbar, it will be a height based calculation something like this
element.offsetHeight - element.clientHeight
?
In a nutshell, for horizontal scrollbars, check the scrollbars based on height calculation, and for vertical scrollbars it's vice versa.
Upvotes: 0
Reputation: 1437
This function takes an element and a direction (either vertical
, horizontal
, or both
) as arguments and returns true
if the element has scroll bars in the specified direction(s), and false
otherwise.
function hasScrollbar(el, direction = 'both') {
const style = window.getComputedStyle(el);
if (direction === 'vertical' || direction === 'both') {
if (el.clientHeight < el.scrollHeight || style.overflowY === 'scroll' || style.overflowY === 'auto') {
return true;
}
}
if (direction === 'horizontal' || direction === 'both') {
if (el.clientWidth < el.scrollWidth || style.overflowX === 'scroll' || style.overflowX === 'auto') {
return true;
}
}
return false;
}
Test on this page:
hasScrollbar(document.querySelector('.lang-js.s-code-block'), 'vertical')
Upvotes: 2
Reputation: 2376
If you need to know if theres a scrollbar present for the whole webpage and with full browser support you can use this:
const hasScrollbar = document.body.scrollHeight > window.innerHeight
It's important to use window.innerHeight
instead of document.body.clientHeight
because in some mobile browsers clientHeight will not get the size of the address bar but scrollHeight will, so you get wrong calculations.
Upvotes: 3
Reputation: 677
There are several problems in case of checking the existence of scrollbars one of which is that in mac you don't have any visible scrollbar so both all the solutions above wouldn't give you an accurate answer.
So because the browser's rendering isn't very frequent you can check the having scroll with changing scroll and then setting it back:
const hasScrollBar = (element) => {
const {scrollTop} = element;
if(scrollTop > 0) {
return true;
}
element.scrollTop += 10;
if(scrollTop === element.scrollTop) {
return false;
}
// undoing the change
element.scrollTop = scrollTop;
return true;
};
Upvotes: 5
Reputation: 57271
For IE11 (Internet Explorer 11) I had to change the logic to:
// Subtract 3 (a small arbitrary number) to allow for IE reporting a difference of 1 when no scrollbar is present
var hasVerticalScrollbar = div.scrollHeight - 3 > div.clientHeight;
This is because IE reports scrollHeight as 1 larger than clientHeight when no scrollbar is present but approx 9 larger when a scrollbar is present
Upvotes: 1
Reputation: 860
none of this answers are correct. you have to use this :
var div = document.getElementById('container_div_id');
var hasHorizontalScrollbar = (div.offsetWidth > div.clientWidth);
var hasVerticalScrollbar = (div.offsetHeight > div.clientHeight);
Upvotes: -8
Reputation: 2200
I found this somewhere a couple of weeks ago. It worked for me.
var div = document.getElementById('container_div_id');
var hasHorizontalScrollbar = div.scrollWidth > div.clientWidth;
var hasVerticalScrollbar = div.scrollHeight > div.clientHeight;
/* you'll get true/false */
Upvotes: 208
Reputation: 3531
Here is yet another solution:
As a few people pointed out, simply comparing offsetHeight and scrollHeight is not enough since they differ on elements with overflow hidden, etc., that still don't have scrollbars. So here I'm also checking if overflow is scroll or auto on the computed styles for the element:
var isScrollable = function(node) {
var overflowY = window.getComputedStyle(node)['overflow-y'];
var overflowX = window.getComputedStyle(node)['overflow-x'];
return {
vertical: (overflowY === 'scroll' || overflowY === 'auto') && node.scrollHeight > node.clientHeight,
horizontal: (overflowX === 'scroll' || overflowX === 'auto') && node.scrollWidth > node.clientWidth,
};
}
Upvotes: 16
Reputation: 173
Just messing around here as none of the above solutions worked out for me (so far). I have found some success with comparing a Div's scrollheight against its offsetHeight
var oh = $('#wrapDiv').get(0).offsetHeight;
var sh = $('#wrapDiv').get(0).scrollHeight;
It seems to give me an acurate comparison...so far. Does someone know if this is legitimate?
Upvotes: -1
Reputation:
I maybe a little late to the party, but...
I believe you can detect for scrollbars with e.offsetWidth vs. e.clientWidth. Offset width includes borders and scrollbars, padding and width. Client width includes padding and width. Please see:
https://developer.mozilla.org/en/DOM/element.offsetWidth (second image) https://developer.mozilla.org/en/DOM/element.clientWidth (second image)
You need to check:
Do the same for the vertical (offset/clientHeight).
IE7 reports a clientHeight of 0 for some elements (I haven't checked why), therefore you always need the first overflow check.
Hope this helps!
Upvotes: 6
Reputation: 322622
This may seem (or be) a little hackish, but you could test the scrollTop
and scrollLeft
properties.
If they're greater than 0, you know there are scrollbars. If they're 0, then set them to 1, and test them again to see if you get a result of 1. Then set them back to 0.
Example: http://jsfiddle.net/MxpR6/1/
function hasScroll(el, direction) {
direction = (direction === 'vertical') ? 'scrollTop' : 'scrollLeft';
var result = !! el[direction];
if (!result) {
el[direction] = 1;
result = !!el[direction];
el[direction] = 0;
}
return result;
}
alert('vertical? ' + hasScroll(document.body, 'vertical'));
alert('horizontal? ' + hasScroll(document.body, 'horizontal'));
I believe there's a different property for IE, so I'll update in a minute with that.
EDIT: Appears as though IE may support this property. (I can't test IE right now.)
http://msdn.microsoft.com/en-us/library/ms534618(VS.85).aspx
Upvotes: 19
Reputation: 1007
Try:
For vertical scroll bar
el.scrollHeight > el.clientHeight
For horizontal scrollbar
el.scrollWidth > el.clientWidth
I know this works for IE8 and Firefox 3.6+ at least.
Upvotes: 19