Creating custom scrollpane using JavaScript


Русская версия статьи.

What's in this article?

I will explain how in nearly 10 minutes you can create a custom scrollpane for your website with the help of the jScrollPane, a jQuery library, and how to style and customize it.

Basic information

Sooner or later every webdesigner will face the following problem: scrollpanes on the website that he is creating just do not fit in the design (and every browser renders it differently). In many cases this is not a big deal, but there are customers who pay attention to it. They insist that scrollpanes, for instance, should have specific color, rounded corners and should not have navigational arrows. So how do we achieve this? Can CSS help us with this issue? Well, some years ago I have met websites that implemented some CSS instructions to paint window scrollpanes differently, but it only worked in a well-known browser called Interner Explorer starting from version 6. So this solution cannot help in our case. Still if someone is interested in how this is done, here are the relevant CSS instructions:

body {
   scrollbar-face-color: green;
   scrollbar-highlight-color: blue;
   scrollbar-3dlight-color: red; 
   scrollbar-darkshadow-color: yellow; 
   scrollbar-shadow-color: grey; 
   scrollbar-arrow-color: purple; 
   scrollbar-track-color: pink;
}

We'll assume that there is a certain block on our website that requires custom scrollpane, a block with users' comments, for example (quick example can be found on this website: just open this article and scroll to the bottom of the page; you will see comments block that implements custom scrollpane). Our HTML markup will be dead simple:

<div id="comments_block">Our text goes here.</div>

CSS styles:

#comments_block {
   overflow: auto;
   width: 700px;
   height: 200px;
}

Later you should adjust width and height for your website. Here is what we've got so far:

Now we need some magic to turn this ordinary scrollpane to custom. Here comes jScrollPane, a plugin for jQuery, that will surely help us. It was written by Kelvin Luck and its official website is http://jscrollpane.kelvinluck.com. You can download the latest version of this plugin from this page; the code was already minificated by caring author. Do not forget to hook up jQuery on your website prior to integrating jScrollPane (plugin does work with the latest jQuery). Apart from JavaScript code we will also need some basic styles, which can be downloaded here; later you can modify it to style your scrollpane. Also it is recommended to hook up a plugin that provides mousewheel support for our users. It is called MouseWheel and it was written by Brandon Aaron. Latest version of this plugin can be downloaded from the GitHub (this script also can be found on jScrollPane's website). The last (but not the least :)) script that we can include is MouseWheelIntent plugin, that provides better mousewheel support - user can use mousewheel even if one container with custom scrollpane is nested into another. Using this plugin is absolutely optional but can increase usability of your website. Warning! There is a link to download MouseWheelIntent on jScrollPane's website but the suggested version will not work with latest jQuery because it uses some undocumented methods that are not supported anymore. I have tweaked this library, updated version can be found here (I wanted to contact the author but his website is not available and I could not find any other information about him; if you have got any information about this person please contact to me :)).

There are various useful examples on jScrollPane's website, so I will describe only a couple of them. For now we'll just try to turn our scrollpane to a custom one. The following simple JavaScript code will do the trick:

$(document).ready(function() {
   $('#comments_block').jScrollPane();
});

Here we wait for the page to load, and then we call jScrollPane() on our container with an ID of #comments_block.

We also have to slightly modify our markup. If we leave our #comments_block as it is now, then jScrollPane will work incorrectly: default scrollpane will be gone but custom will not appear. This bug is not fixed yet. To solve this problem we just have to wrap the text inside out block #comments_block with any block tag, for example p, div or ul (if you are planning to use unordered list). So our markup transforms into this:

<div id="comments_block"><p>Our text goes here.</p></div>

Here is the result:

Yay, it worked! Now we just have to apply some styling to our scrollpane. Lets make it in grey colors and make it more narrow (I also have to note that there is a theme for jScrollPane available):

.jspVerticalBar {
   width: 8px;
}
.jspTrack {
   width: 8px;
   background-color: #ededed;
}
.jspDrag {
   width: 8px;
   background-color: #ccc;
}

Customizing jScrollPane

You have probably noticed that scrolling with mousewheel is too slow. Well, this can easily be fixed - jScrollPane allows to pass many parameters for customization (the full list of available parameters can be found here):

$('#comments_block').jScrollPane({mouseWheelSpeed: 70});

The speed of 70 should be enough (at least it is okay in my point of view), but you can play with it a bit more (default value is 10).

Another useful parameter says whether our block with custom scrollpane should be reinitialised automatically. When should we use it? For example, you can use it when your block has relative a width (that can be specified in %). In this case when users change window size, scrollpane should be re-rendered accordingly (it is not done automatically by default). You can either do it via jScrollPane's API (we will talk about it later) or you can use this:

$('#comments_block').jScrollPane({autoReinitialise: true});

So scrollpane will be reinitialised automatically. This parameter can also be used when a content is added dynamically to the block with jScrollPane. Without automatic reinitialization scrollpane will not be updated and our new content will basically be invisible to the user and there will be no way to scroll to it (it will be located beyond the block's borders). So autoReinitialise parameter fixes this problem. Please note that automatic reinitialization is done rather frequently - every 0.5 seconds. If you want your block to be reinitialized every, say, 5 seconds, then use another parameter autoReinitialiseDelay:

$('#comments_block').jScrollPane({autoReinitialise: true, autoReinitialiseDelay: 5000});

The value passed is in milliseconds.

Please also note that when a block with jScrollPane is focused, a user can scroll with "up" and "down" keys. If you want to disable this feature, set enableKeyboardNavigation parameter to false.

jScrollPane's API

The last but no the least is the jScrollPane's API that may come in really handy. Accessing API is easy:

var my_comments_block = $('#comments_block').jScrollPane();
var api = my_comments_block.data('jsp');

Now an api variable can be used to invoke jScrollPane's API methods. For example, this code

api.reinitialise();

invokes reinitialization of the scrollpane (also don't forget that you can use autoReinitialise parameter in order to make this automatic). Another useful method is scrollToElement that can be used to scroll to a specified element; this element is passed as a first argument and can be represented as a jQuery object, DOM node or jQuery selector. The second argument passed is a logical value - true or false - that controls whether the specified element should stick to the top of the block. If this argument is set to false then jScrollPane will scroll as little as possible to show the element. The third parameter is also a logical value that controls whether scrolling should be animated. Lets demonstrate this method. For this we will have to slightly modify our markup:

<a href="#" class="scroll_to_element">Scroll to element!</a>

<div id="comments_block">
   <div>
      <p>Text</p>
      <p class="scroll_to_me">Scroll to me!</p>
      <p>More text</p>
   </div>
</div>

We are going to put some more lines of text inside our block and also add a paragraph with a .scroll_to_me class - we will make our script to scroll to this element. There will be a link with a class of .scroll_to_element at the beginning of the page. Clicking this link will make scrollToElement method being triggered; this method will scroll to the desired element. Here comes the JavaScript code:

$(document).ready(function() {
   var my_jsp = $('#comments_block').jScrollPane({});
   var api = my_jsp.data('jsp');

   $('.scroll_to_element').click(function(e) {
      e.preventDefault();
      api.scrollToElement('.scroll_to_me', true, true);
   })
});

Firstly we assign an api variable that will be used to access jScrollPane's API and then we bind an event handler for a click event to a link with a class .scroll_to_element. When the link is clicked, the default action will be stopped using the preventDefault() method (otherwise the browser will try to open this link) and then we invoke scrolling to the specified element; we also pass two boolean arguments set to true in order to make the element stick to the top and to animate scrolling.

There are also a handful of methods that perform a similar task: scrollTo (scroll to a specified point that is being described as x and y coordinates counting from top left corner of the container); scrollToX and scrollToY (scroll to a specified point on x or y axis); scrollToPercentX and scrollToPercentY (scroll by specified percentage on x or y axies) and some other. Apart from that we can also get some information about the scrollpane with the help of API: getIsScrollableH and getIsScrollableV (whether scrollpane can be scrolled by x or y); getContentPositionX and getContentPositionY (get the current x or y position of the viewport with regards to the content pane); getPercentScrolledX and getPercentScrolledY (get the horizontal or vertical position of the viewport within the pane content) and more. And lastly we can destroy jScrollPane and bring back default scrollpane to the container using destroy method.

Thats all for now. As we saw, this library provides not only a variety of options to customize scrollpane, but also an API to work with. jScrollPane is constantly being improved so if you find a bug or want to request some feature feel free to open a new issue on GitHub. Don't forget to describe your problem thoroughly if you are reporting a bug.

For Ruby on Rails developers

There is also a small bonus for Ruby on Rails developers: you can easily include jScrollPane and other libraries described here into your project. Add this line gem 'jscrollpane-rails' to your Gemfile to include jScrollPane. This gem was written by me; I constantly update it and so you can be sure that you are using the latest code. Don't forget to run bundle install command and then drop //= require jquery.jscrollpane to your application.js and *= require jscrollpane to application.css. Also do not forget to require jQuery.

If you also want to use MouseWheel, add gem "jquery-mousewheel-rails" to your Gemfile, install the gem and drop //= require jquery.mousewheel to the application.js. jquery-mousewheel-rails gem was written by Mike MacDonald.

And lastly you may also include MouseWheelIntent to your project. To do this, add gem "mwheelintent-rails" to the Gemfile, run bundle install and then add //= require jquery.mwheelintent to the application.js. mwheelintent-rails gem was also written by me.

I hope that these gems will be useful for you. Please post your questions using comments. Good luck and see you in the next articles!

Follow me on Twitter to get updates about new articles >>