67

I am trying to create my own scroll bars. I have tried most of the jquery scrollbar plugins and none of them seem to work for me, so I decided to create my own. I have an overflow area with scrollable content. I can get the scrollbar to work if I am able to figure out the height of the scrollable content area. I have tried .scrollHeight() and the browser doesn't even recognize it. The overflow area has a fixed position.

isherwood
  • 58,414
  • 16
  • 114
  • 157
mtlca401
  • 1,413
  • 4
  • 16
  • 24

6 Answers6

138

scrollHeight is a property of a DOM object, not a function:

Height of the scroll view of an element; it includes the element padding but not its margin.

Given this:

<div id="x" style="height: 100px; overflow: hidden;">
    <div style="height: 200px;">
        pancakes
    </div>
</div>

This yields 200:

$('#x')[0].scrollHeight

For example: http://jsfiddle.net/ambiguous/u69kQ/2/ (run with the JavaScript console open).

mu is too short
  • 426,620
  • 70
  • 833
  • 800
  • 1
    Every where I read about scrollHeight, no one ever said that the [0] was needed and that scrollheight is not a function. I'm assuming, after trying this, that I got the correct height. I will not know until I implement the calculations for the scrollbar. But, you get the points. Thanks! – mtlca401 Jul 28 '11 at 02:07
  • 7
    @mtlca401: You need the `[0]` to extract the underlying DOM object from the jQuery object, that gives you the same sort of thing that `document.getElementById()` will give you. You can also use jQuery's [`get`](http://api.jquery.com/get) function. – mu is too short Jul 28 '11 at 02:10
  • I get 4260px in chrome and 4300px in firefox, but I'm assuming this is because of padding maybe? Is this correct? – mtlca401 Jul 28 '11 at 02:11
  • @mtlca401: could be a lot of things (margins, paddings, line-height, font rendering differences, ...), ~1% difference isn't that much. – mu is too short Jul 28 '11 at 04:02
  • 2
    If you want the actual scrollTop height you will need scrollLength = $('#x')[0].scrollHeight - $('#x').height(); – mbokil Sep 18 '13 at 15:07
  • @Alvaro: Is Opera 12 the old Opera or Opera-Next? What does "not work" mean? – mu is too short Oct 31 '13 at 16:27
  • Well, I mean that it doesn't calculate the content height correctly. If the container has a fixed height with `overflow:scroll`, then it gets the `height` of the container, not of the content. I talk about Opera 12.16, the old version of Opera browser, which still being used by many people. The last version which doesn't include Webkit engine. – Alvaro Oct 31 '13 at 16:30
33

If you can possibly help it, DO NOT USE .scrollHeight.

.scrollHeight does not yield the same kind of results in different browsers in certain circumstances (most prominently while scrolling).

For example:

<div id='outer' style='width:100px; height:350px; overflow-y:hidden;'>
<div style='width:100px; height:150px;'></div>
<div style='width:100px; height:150px;'></div>
<div style='width:100px; height:150px;'></div>
<div style='width:100px; height:150px;'></div>
<div style='width:100px; height:150px;'></div>
<div style='width:100px; height:150px;'></div>
</div>

If you do

console.log($('#outer').scrollHeight);

you'll get 900px in Chrome, FireFox and Opera. That's great.

But, if you attach a wheelevent / wheel event to #outer, when you scroll it, Chrome will give you a constant value of 900px (correct) but FireFox and Opera will change their values as you scroll down (incorrect).

A very simple way to do this is like so (a bit of a cheat, really). (This example works while dynamically adding content to #outer as well):

$('#outer').css("height", "auto");
var outerContentsHeight = $('#outer').height();
$('#outer').css("height", "350px");

console.log(outerContentsHeight); //Should get 900px in these 3 browsers

The reason I pick these three browsers is because all three can disagree on the value of .scrollHeight in certain circumstances. I ran into this issue making my own scrollpanes. Hope this helps someone.

Shazboticus S Shazbot
  • 1,289
  • 2
  • 16
  • 27
33

We can also use -

$('#x').prop('scrollHeight') <!-- Height -->
$('#x').prop('scrollWidth')  <!-- Width -->
Aaron Sherman
  • 3,789
  • 1
  • 30
  • 33
Anmol Saraf
  • 15,075
  • 10
  • 50
  • 60
5

Element.scrollHeight is a property, not a function, as noted here. As noted here, the scrollHeight property is only supported after IE8. If you need it to work before that, temporarily set the CSS overflow and height to auto, which will cause the div to take the maximum height it needs. Then get the height, and change the properties back to what they were before.

Sajid
  • 4,381
  • 20
  • 14
  • https://developer.mozilla.org/en-US/docs/Web/API/Element.scrollHeight says IE 8 is the lowest version it supports, so it would be "after IE7" or "IE8 and later" – Matthew Flaschen Jan 07 '15 at 20:47
2

You can get it with .outerHeight().

Sometimes, it will return 0. For the best results, you can call it in your div's ready event.

To be safe, you should not set the height of the div to x. You can keep its height auto to get content populated properly with the correct height.

$('#x').ready( function(){
// alerts the height in pixels
alert($('#x').outerHeight());
})

You can find a detailed post here.

Laurel
  • 5,965
  • 14
  • 31
  • 57
Language Lassi
  • 2,520
  • 21
  • 24
1
  1. Using scrollHeight is not only buggy, but doesn't work when your container has a hardcoded height (which is probably most cases, since you wanna get contents height without doing container.height() itself)
  2. @shazboticus-s-shazbot solution is good when you can mess around with the container height temporarily / have a hard-coded height.
  3. An alternative solution would be:

$('#outer')
    // Get children in array format, as we'll be reducing them into a single number
    .contents().toArray()
    // Filter out text and comment nodes, only allowing tags
    .filter(el => el.nodeType === 1)
    // Sum up all the children individual heights
    .reduce((accumulator, el) => $(el).outerHeight(true) + accumulator, 0);

Of course, this latter alternative only works when #outer doesn't have immediate text childrens that take up space and you want to measure. Those are my 2 cents.

  1. If you want to measure unwrapped text, I'd suggest modifying your DOM tree and having an inner <div> of which you can measure easily by doing $('#outer').children().height()
Tom Roggero
  • 5,777
  • 1
  • 32
  • 39