Custom Scrollbars

I've been developing a portal site using ruby on rails and script.aculo.us and I wanted to be able to scroll the contents of some of the 'portlets' but I wanted the scrollbars to match the overall appearance of the page, which the standard scrollbars don't. I'd seen this done before so I assumed that script.aculo.us would have implemented such a thing, but they hadn't. I managed to find some examples of scrollable div javascript libraries on the net of which the best are probably fleXcroll and the scrolling layer content page at dyn-web, but I had a couple of concerns like: Would they work if the content were updated via Ajax? Would they live in harmony with script.aculo.us?

So in the end I decided to implement my own (I seem to live my life saying to myself; 'how hard could it be'?). This is the result. It is certainly not as accomplished as fleXcroll, but it works fine if content is updated using Ajax and it re-uses scipt.aculo.us classes so its pretty small and is guaranteed to play nice with it too. (BTW - its based pretty heavily on this one. I couldn't see any licensing terms, but credit where credit is due).

Here is an example:

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

To use, you will need to include the scriptaculous scripts in the page (as it uses them pretty heavily) and then simply include scroller.js in your page, for example:

<script src="/javascripts/prototype.js" type="text/javascript"></script>
<script src="/javascripts/slider.js" type="text/javascript"></script>
<script src="/javascripts/scroller.js" type="text/javascript"></script>

Add the class makeScroll to any div that you want to have a scrollbar, set its overflow style to hidden and make sure it has a height, e.g.:

<div style="height:165px; overflow:hidden" class="makeScroll">
somecontent
</div>

And the script will do the rest.

If you use Ajax to re-write the original div you will need to make sure it has an id and then call Scroller.reset(<id>) once the update is complete. For example if the div has id body_1 then you should call Scroller.reset("body_1") to wrap just that div with a scrollbar.

The appearance of the scrollbar can be controlled using a stylesheet. The scrollbar itself has class scroll-track, the thumb (the part you grab) has class scroll-handle. This is the stylesheet I use at the portal above:

.scroll-track{
 height:10px;
 width:10px;
 background:black;
}

.scroll-handle{
 border: 1px solid black;
 height:10px;
 width:10px;
 background:#5B207B;
 cursor:pointer;
}

Obviously you could set the classes to use images as the background too if you wanted - which is what the examples on this page do.

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

The scrollbar on the left adds buttons at the top and bottom of the bar and adds rounded end-cap to the thumb. These additions (and scrolling using the mouse wheel) have been added by Paul Castle. To add scroll buttons you need to define a CSS style for the classes scroll-track-top and scroll-track-bot. To define end-caps for the thumb you need to define styles for the classes scroll-handle-top and scroll-handle-bot.

You can get the file at my subversion server. Its been tested in Firefox and IE6, so can't say if it works in other browsers. BTW the comments in the file are designed to be rendered using NaturalDocs - which was the only document generator I could find that handled prototype-style JavaScript.

See the NaturalDocs here.

36 Responses to “Custom Scrollbars”

  1. Emrah Baskaya Says:

    Hi Jools, thanks for the reference.. I’d like to correct one thing, fleXcroll is able to cope with ajax changes, just like any other change. Just calling element.scrollUpdate(); after the content is injected is enough. That said, your solution is just fine.

  2. Lance E Sloan Says:

    Too bad it doesn’t support arrow keys, page up/down, or mouse scroll wheels. But then, I haven’t seen a custom scroll bar that does yet.

  3. judge Says:

    I belive fleXcroll supports all of those. I thought I needed scroll arrows too, but the reality is I never actually use them. As for page up/down and scroll wheel support - I agree it would be nice. I will add them when I get time, or if someone else wants to add them I am happy to give them write access to subversion.

  4. Alexandre Plennevaux Says:

    hi!

    i really like your implementation. I would like to use it to display the news on our website, and have it scroll to a specific news item (we publish our upcoming events a few months in advance; it would be nice that it centers to the most current date). So that means, have it scroll to, says, top: -450px;

    Do you think it is possible? Also, do you plan to add more functionalities?

    Anyway, i will try to do it, and also add up/bottom arrows.

    Thanks for sharing!

    Alexandre

  5. judge Says:

    @Alexandre: sure. You should set the slider value as appropriate (i.e. this.slide.setValue(…)).

    Yes I plan to work on it some more - in my case I want to add support for mouse scroll wheels etc. But at the moment I am working on something else. Let me know if you add the functionality you describe.

  6. Alexandre Plennevaux Says:

    Hi judge,

    i’m half way implementing the arrows (i ‘ve modified heavily the decorate() function ).
    I have other scroll controllers ideas, so i’ve set up the html a bit differently: i’ve created a “scrollController” div that contains the arrows and the scrollbar. it didn’t break anything so far :)
    Now, i’m about to add the actual scroll up / down behaviors. That’s a good lesson for someone that is not used to javascript :)
    I hope i’ll manage, and let you know…

  7. Alexandre Plennevaux Says:

    Hi judge,

    at this point i have a working version of the scrollUp/Down buttons. It’s far from perfect, but i need some help/ tips.
    Like, for the moment, i can scroll per “click” event, but if i do it onmousedown, or onmouseover, it just does it once, and not continuously.
    I would be grateful if i could show you the code i came up with, maybe you can see if i’m going in the right direction?

    thanks,

    alexandre

  8. Kelvin Luck Says:

    Hi,

    I built something similar but on top of the jQuery library. It’s got up/down buttons and listens to the mouse wheel (including when it’s nested) - you may want to check the code out for ideas on how to add these functionalities to yours…

    jScrollPane page

    Some more examples

    Cheers,

    Kelvin :)

  9. TripleSix Says:

    I have a problem with this implementation of the custom scrollbars. Whenever I try to add a border to either left or right side in the ’scroll-track’ class, the whole scrollbar disappears in Firefox, leaving just the space freed up by the script.

    Everything works fine in IE though.

  10. Christian Fecteau Says:

    I’m coding the UI for a site that uses the Rails/Prototype/Scriptaculous trio and the customer doesn’t have much money so instead of coding my own custom scroller, I went with yours. Thank you very much for your scroller. You should put credits in the source code. I will put a link to this page.

    I have pages with A LOT of content so the JS needs to be optimized. I had to change a few things in your code for performance reasons as well as one thing that was just wrong: never ever use innerHTML to manipulate DOM elements. This is a poor toString() method that will screw up other scripts modifying the DOM simultaneously. That was my case and I had to rewrite your code:
    while (this.outerBox.hasChildNodes()) {
    this.innerBox.appendChild(this.outerBox.firstChild);
    }
    this.outerBox.appendChild(this.innerBox);
    //this.innerBox.innerHTML = this.outerBox.innerHTML;
    //this.outerBox.innerHTML=”";
    The other things are less important. One is an iteration with a for…in that should not be used with Prototype:
    http://prototypejs.org/api/array

    Scroller.updateAll = function () {
    $H(Scroller.ids).each(function(pair) {
    Scroller.ids[pair.key].resetScrollbar(true);
    });
    }

  11. Roy Says:

    Love it! So light weight and easy to manage.

    Any chance you’ve started working on enabling wheel scroll?

    I guess another feature you could have - like you don’t have enough on your plate as it is - is having up and down buttons, not just a scrollbar.

    Thanks again!

  12. Tarun Says:

    Hi Guys,

    this custom scroll bar is not compatible with mozilla 1.5. if any body know how can i compatible it with mozilla1.5. please suggest me.

  13. Soledad Vel Says:

    Hi, I met one problem. it is happening when i look the scroller with Internet Explorer 6. I click over the scrollbar thumb and start to drag it. At this moment, the image used to be the thumb dissappears, and it appears after some seconds. In the satus bar it seems like it is loading the image again. Why is this happening and how can it be avoided?
    Thanks

  14. NZo Says:

    Hi,
    i was looking for a slider like this that works with Ajax. It’s ok with Firefox but not with IE7, Safari 2 or Safari 3. And yes, i’m using the Scroller.reset after the ajax update! if somebody has a suggestion…

    Thanks

  15. Joao Rodrigues Says:

    I’ve not tested with IE7 but i have a working version on Safari 3.0.2.
    I’m also using YUI Animated Scrolling (http://developer.yahoo.com/yui/examples/animation/scroll.html) buti i cannot see how to combine the automatic scrolling from YUI with the placement of the scrolling Any help ?

  16. Jason Says:

    I’m wondering if this will work inside of Lightwindow from Stickmanlabs. Before I found your prototype script, I tried merging jQuery with LW. It showed up, but won’t go away…like a bad house guest.

  17. Scrollbars in CSS - TalkPHP Says:

    […] As Aaron already said, scrollbar colors are only supported by IE and partially by Opera. Quirksmode has a good browser support list that verifies that statement. If you want a crossbrowser solution you should use javascript, i.e. flexscroll, scroller.js using the prototype library or jScrollPane for jQuery. […]

  18. Distorto Says:

    What brilliant work - between fleXcroll and this, I’m in scrolling heaven. I’m now purposefully making every element in all pages scrollable. In fact, now my wife and cat are both scrollable.

    Re: people who are seeing oddities in Firefox, I did too for a short time… had to remove scriptaculous transitions and after doing so, the scroller appears for me in firefox, ie and safari so far w/out problems.

    Problematic code:
    new Ajax.Updater(’divScroll’, page, {onComplete:function(){ Element.hide(’divScroll’); new Effect.Appear(’divScroll’); Scroller.reset(’divScroll’); }, asynchronous:true, evalScripts:true});

    Happy code:
    new Ajax.Updater(’divScroll’, page, {onComplete:function(){ Scroller.reset(’divScroll’); }, asynchronous:true, evalScripts:true});

  19. Ash Says:

    Hi this may be blatently obvious but how can i get a link within the scolled text to change the vertical position of the scrolled text itself.

    For example, I have a block of faq text to go in the scroll box. This content consists of all the questions at the top of the list, followed by each question and answer in order. So the customer can just scroll down through them at their leisure or click on any of the questions to jump to that question exactly.

    I saw in a previous comment

    this.slide.setValue(…)

    but alas i am lame at javascript and i don’t even know how to target the javascript object from a link within the html.

    Can someone please give me an example, preferably with a brief explanation of how and why please?

    Thanks, great script by the way!

  20. Clemens Kofler Says:

    I’m having troubles getting these scrollbars to work with Scriptaculous’ Autocompleter. Sometimes, it seems, the page decides to load the scrollbars and sometimes it doesn’t. Funny thing is: When it doesn’t load the scrollbars, autocompletion works perfectly fine - but when it does load the scrollbars, the Autocompleter doesn’t work (it doesn’t send the AJAX request so I guess the change event doesn’t fire properly).

    Has anyone had similar problems? If so, it would be great if you could contact me at clemens [ at ] railway [ dot ] at.

    Thanks a lot,
    - Clemens

  21. Distorto Says:

    I’ve been so very happy with both jlog and flexcroll… until the dreaded Microsmut opened the gaping ugly maw of IE8…

    Can the developers or our forum friends say if these will ever be IE8 compatible? I have a feeling that I may be forced back to standard scrollbar hell. Which really isn’t hell. Just bland purgatory.

    Sean

  22. judge Says:

    There’s always hope. I’ve not used IE8. If Scriptaculous works with it then there’s a shouting chance that I might make this work.

  23. Christian Says:

    Hi,

    Nice Work, But actually I ran into deep problems: As long as i use it without extra windows, everything works as expected. But if i try to get the scrollbars work in a “different window” like the prototype implementation of a window ( http://prototype-window.xilinus.com ) I don’t get the scrollbars working.

    Does anybody have an idea how to get the scrollbars work in a window created by prototype’s window implementation ?

    Thanks for any suggestions.

  24. Devon Says:

    Hi Judge,

    Great script - my scrollbars look vastly improved now!

    I do have one little thing I’m wrestling with though. When I have tags that jump further down a page (for example in an FAQ where the questions are up at the top and then the answers are down further) I cannot seem to get the scrollbar to redraw when someone clicks on a question and is jumped down the page. Any suggestions you can provide would be sincerely appreciated!

    Thanks,
    Devon

    Here’s some sample code:

    1. Question 1

    1. Question 1’s answers

  25. CyberCastle Says:

    The script with extra features I sent to your mail (js + css).

    Greetings

  26. judge Says:

    Thanks. I’ve incorporated your mods into the script and updated the article to describe them.

  27. CyberCastle Says:

    This Script was tested in IE7, Firefox 3.0.1 (Win and Linux), Opera 9.51 (Win) and Safari 3.1.2 (Win only) by me, whitout problems apparently.

    Greetings, Paul Castle

  28. Rick sarvas Says:

    Hey Judge,
    Nice job with the code! Any chance you can add an option to keep the scroll-handle element a fixed height rather than automatically sizing based on content (though that is a *very* nice touch)?

    I’m working on a band web site for a friend of mine and I wanted to use a fixed size guitar pick image as the scroll handle. I’ve tried setting the scroll-handle-top and scroll-handle-bot CSS elements to be the top and bottom halves of the image (that part works fine), but I can’t seem to force the scroll-handle element to be of zero height. Having the code check for a forced zero height before overriding the value with an auto scaling the scroll-handle height would be nice.

  29. coder Says:

    i am not able to implement .scroll-track-top and .scroll-track-bot and i also found out that on your site you have used css for id -> #scroll-track-top-2 and #scroll-track-bot-2. on my local server , scroll-track-top-1 is created instead of scroll-track-top-2. can you please confirm why different ids are being generated on my local server?

  30. judge Says:

    The CSS class (.scroll-track-top etc.) should work. If you’re using Firefox with Firebug installed, take a look at the elements and you will see that that class is defined.

    The id (e.g. scroll-track-top-1 etc.) is generated per-scrollbar - the first scollbar will have an ID of scroll-track-top-1, the second scroll-track-top-2 etc.

  31. coder Says:

    thanks for the details but i am still not able to use those scroll-track-top/scroll-track-bot classes and one thing which i found out on my local server is that scroll-track is taking same height as scroll-innerBox whereas on this page they are of different heights i.e scroll-track = height:145px and scroll-innerBox = height:165px. the remaning 20px height is taken by scroll-track-top and scroll-track-bot evenly. i wonder if any one else has faced the same issue?

  32. Victor Says:

    Amazing script!!! Never knew implementing custom scrollbars could be this easy. Thanks for making it so simple.

  33. Alex Says:

    Thank you SOOO much, truly awesome, saved my day.
    Great solution, easy, not too hard to tweak, already love the scriptaculous, perfect.
    Great service to everyone.

  34. Tom Says:

    The scroller grabs every mouse wheel event of a mouse hovering over a div with the class makeScroll and does not distinguish between divs with added scrollbars and those without.

    The solution is to cut the lines

    this.domMouseCB = this.MouseWheelEvent.bindAsEventListener(this, this.slider);
    this.mouseWheelCB = this.MouseWheelEvent.bindAsEventListener(this, this.slider);
    this.trackTopCB = this.tracktopEvent.bindAsEventListener(this, this.slider);
    this.trackBotCB = this.trackbotEvent.bindAsEventListener(this, this.slider);

    //Events control
    $(this.outerBox).observe(’DOMMouseScroll’, this.domMouseCB); // Mozilla
    $(this.outerBox).observe(’mousewheel’, this.mouseWheelCB);// IE/Opera
    $(this.tracktop).observe(’mousedown’, this.trackTopCB);
    $(this.trackbot).observe(’mousedown’, this.trackBotCB);

    from line 151 ff and paste them to the if (this.innerHeight

  35. Tom Says:

    Due to the comment restrictions, here is the rest of it:

    Cut the lines and pasthe them inside the if (this.innerHeight

  36. Tom Says:

    OK, html problem:

    cut the lines and paste them inside the if (this.innerHeight < this.innerBox.scrollHeight) block

Leave a Reply