Categories

Close

Design Lunatic

Custom Scrollbars with jQuery

Sometimes, as web designers, we create a perfect design. Everything is exactly the way it should be, every pixel in the right spot, every color the right tinge. However, there is one thing that we often leave unchanged, and that is the scrollbar. Today, I’ll show how to create custom scrollbars using jQuery.

HTML

The HTML is extremely basic – it’s just a “section” with some paragraphs inside. The javascript we’re about to write inserts all the HTML the custom scrollbar needs, so you can place whatever you want into the HTML.

<section id="main">
<p>
Lorem ipsum dolor sit amet, christus eum ego. Rhenum ibat est amet consensit cellula filia in lucem. Maria non dum est Apollonius eius sed quod una litus ostendam Apollonio dares. Actum in rei civibus nescis admonente iustum ait in deinde duas particularis ad quia ad per dicis. Stans sed quod una Christi iube es est cum, athenagorae principio intus huius domus ad quia quod tamen adnuente rediens eam ad per. Quos essem rogo cum suam non ait mea in rei sensibilium acciperem. Corripit ars tolle Adfertur guttae sapientiae decubuerat. Inquisivi ecce habitu rubor virginitatem sunt antecedente tuus desiderio sic ut libertatem adhuc. Inter autem nobiscum paulo aureos fecit per accipere, dicis Deducitur potest flens praemio litore iunctionem quae. Domini in lucem genero in rei finibus veteres hoc! Equidem deceptum in deinde cepit roseo ruens sed eu fugiens laudo in.
</p>
<p>
Lugens quia iuvenis eum istam provoces Athenagora eius sed dominum oculos ne a civitas iter. Patriam Dianae non solutionem inveni quem suis alteri formam speciosam at at eius ad quia illum decidat quam cara patrem! Habes prima inrumpit dic hoc ambulare dolor invenerit, mytilenam Descendi eam in rei finibus veteres hoc. Inquisivi ecce prima substantiae Apollonius in deinde duas formis ei quoque non solutionem innocentem vis! Ait mea ego dum miror diligere quem est se in modo genito in. Adiuro me naufragus qui enim, unam emanabat cum obiectum ait. Miscetur vulnus fertur ardeat in modo genito in fuerat est se ad per animum est amet amet Cur meae. Antiochia videns de tuae illa caelum ad suis. Peregrini in lucem concitaverunt in rei finibus veteres hoc contra serpentibus isto. Post petiit materia amicis filia dedit beneficio ad quia ei. Accedens est cum obiectum est in fuerat se est cum suam vidit Dionysiadi me in. Eum est amet constanter approximavit te in lucem exitum vivit. Se vero non solutionem ascendens sed eu fugiens laudo misera haec vidit ad quia. Impietatem die audi discipuli Tyrius tu mihi Tyrum reverteretur ad nomine.
</p>
<p>
Laetare quod non solutionem invenerunt ita in. Abstulit meis dolor ad per sanctus ait. Probo artium studiose rosa ad per animum pares terris restituit. Meam ad quia iuvenis omnia bono quomodo possum es. Modum cura supponere ipsa Invitamus me! Erige me in deinde vero quo sanctis oravit. Antioche in fuerat eum ego dum miror puella est se ad nomine Maria non ait mea ego esse haec. Atqui plurium venenosamque serpentium ne civitatis civium currebant in, nescimus de me in deinde cupis hominem. Rogo ultimum favente his domino ab ornabo in modo invenit quasi plena violatam. Mutilenae ratio omnes deo adiuves finem. Credo puella mihi quidditas tuo dolor virgo permitte a civitas ad nomine Maria non ait est amet amet amet consensit cellula rei exultant deo. Maria cum unde non dum est amet consensit cellula filia puella. Ascendi in lucem exitum atque bona dei fundamus magister. Thebaeorum in fuerat eum est amet amet constanter determinatio debitis torporis quin.
</p>
<p>
Dicite enim formam se est in! Ardalio nos filiae gloriam virginis provolutus volo lacrimis colligantes amarissimo formas. Secundis est in modo ad suis alteri si non solutionem invenisti naufragus ferro conparuit de. Ni fluctus evasit dic ego illum Apollonii appropinquat tation ulterius a his e contrarius haec vidit Dionysiadi me in. Videns sed quod eam sed quod una Christi in lucem in fuerat accidens suos exteriores. Tantus puella sed haec aliquam habet comam apodixin mei in fuerat est se sed dominum sit in. Ephesum iube creasti hoc ait Cumque materia amicis in modo cavendum es ego dum est Apollonius ut a. Accede meae ad quia ad per te in rei completo litus vita Apolloni figitur acquievit. Etiam corpusculum subito animal irruit in, primam qui enim est in deinde plectrum anni ipsa Invitamus me.
</p>
<p>
Puto suam in lucem genero in fuerat accidens suos exteriores iuvenis eum in fuerat eum ego Pentapolim Cyrenaeorum. Nescimus de me naufragus habuisti sit in! Pater ostendit qui non ait Cumque materia eam eos. Litus sua Cumque persequatur sic vero cum suam ad per dicis filiam in lucem in. Horreo Athenagora eius non solutionem invenisti naufragus ait mea, unam emanabat cum autem illud huius domus respexit est amet coram regis fine omnino vero cum. Habet vero quo accumsan in rei finibus veteres hoc contra me. Permansit in lucem in deinde cupis ei Taliarchum. Ite in modo ad suis alteri si. Ecce codicellis desinit sestertia habeatis Apollonio sed dominum depressit filia navem causa alia qui auri. Sed eu fides se est amet coram regis suam! Quantum ait regem consolatus dum est se sed dominum depressit filia puella ut diem finito convocatis ad per. Ubi diceret modiorum fudit animo resignasset iubet contremuit in, spongia non solutionem inveni in rei sensibilium iussit divisit calvus dolor invenerit. Thebaeorum in rei completo litus sua in fuerat est in. Mutilenae ea communia ei quoque sed quod eam in, fige omnium ad quia ei sed eu fides Concordi fabricata ait. Iacentem substantiales statim iuxta quia iuvenis ut libertatem petitiones, adfertur guttae sapientiae ducitur multa confert eam sed.
</p>
</section>

CSS

The CSS is mostly just styling, but there are a couple of things it is important to have.

html {
overflow-y: hidden;
}

This causes the default scrollbar to disappear, which allows us to create a replacement.

Next, we have the scrollbar track. This is the vertical line on which the scrollbar goes up and down.

#scrollbar-track {
width: 10px;
position: fixed;
right: 0px;
height: 100%;
background: #ddd;
}

We’re giving it a width, fixing it to the viewport so that it stays in the same spot no matter where the user scrolls, we attach it to the right of the screen, and we give it a height of “100%”, which makes it the same height as the viewport. The last thing is just a light grey background.

Next, the scrollbar.

#scrollbar {
width: 10px;
position: fixed;
right: 0px;
background: #666;
-webkit-border-radius: 5px;
border-radius: 5px;
}

The CSS is almost the same as that of the scrollbar track’s, but here there is no “height: 100%”, since the height will vary depending on how much content there is on the page. The scrollbar also has a width of 10px, is attached to the right side of the viewport, and is given some mild styling.

Keep in mind that you won’t be able to see these styles yet, as the elements haven’t actually been created by the javascript yet.

jQuery

The first thing we need is to include a couple of scripts. Download the files for this tutorial. Inside, you’ll find “jquery-ui-draggable.js” and “jquery.mousewheel.js”. The “draggable” script is just a custom build of jQuery UI that only contains the code for “draggable”, and “mousewheel” gives us some handy functions based on the user’s mousewheel or trackpad. Place them in the directory in which you’re following this tutorial.

Now, include them in the “head” of the HTML document.

<script src="jquery.mousewheel.js"></script>
<script src="jquery-ui-draggable.js"></script>

Don’t forget to include a copy of jQuery as well.

Now, we’ll create the scrollbar and the track.

$(document).ready(function(){

	$('body').prepend('<div id="scrollbar-track"><div id="scrollbar"></div></div>');

});

This code adds the two “div” elements we need to the very beginning of the page, just inside the “body”.

Next, we’ll create the function that does all the work.

function scrollBar(){

	var viewportHeight = $(window).height();
	var docuHeight = $(document).height();

	var trackHeight = $('#scrollbar-track').height();

	var scrollbarHeight = (viewportHeight/docuHeight)*trackHeight;

	$('#scrollbar').height(scrollbarHeight);
}

There’s now a function called “scrollBar”, which has some variables inside it. The first one, “viewportHeight” is the height of the browser viewport. The next, “docuHeight”, is the height of the whole HTML page. “trackHeight” is the height of the scrollbar track, which is the same as “viewportHeight”. I just like to keep the two separate to make it clearer what the code actually does. Next, the “scrollbarHeight” variable. This variable is created by taking the ratio of the viewport height to the document height, which is usually between 0 to 1. If the ratio is higher, that means that the viewport is bigger than the whole HTML document, in which case the scrollbar doesn’t do anything. We take the ratio and multiply it by the “trackHeight”. This gives us the height of the scrollbar. Let’s imagine that the whole document is exactly twice as big as the viewport. For example, the height of the viewport is 500px and the height of the document is 1000px. 500/1000 is “0.5″, so the ratio is “0.5″. We then multiply “0.5″ by the trackHeight, which gives us a value exactly half the size of the track height. This is how the height of the scrollbar is determined.

Now, we’ll make the scrollbar draggable.

$('#scrollbar').draggable({
	axis: 'y',
	containment: 'parent',
	drag: function() {
		var scrollbarTop = parseInt($(this).css('top'));

		var scrollTopNew = (scrollbarTop/(trackHeight))*docuHeight;

		$(window).scrollTop(scrollTopNew);

	}
});

This is where the “draggable” script comes in. We use the “draggable” function to make the scroll bar draggable. The “axis” parameter is set to “y”, which means that it can only be dragged up or down. The “containment” parameter is set to “parent”, which means it can’t be dragged out of the boundaries of the parent, which in this case, is the “track”. The last thing is the “drag” paramater, which accepts a function as a value. Basically, whenever the scrollbar is being dragged, this function fires. Inside the function, the first thing we do is create a variable called “scrollbarTop”, which takes the CSS “top” value of the scrollbar (how far away it is from the top of the track) and converts it into an integer. This allows us to use it in mathematical equations such as the one that determines the value of the next variable, “scrollTopNew”. “scrollTopNew” is the new value of where the window should scroll to. In order to do this, we take the ratio of the scrollbar’s “top” value and the “trackHeight”. We then take this ratio and multiply it by the “docuHeight”, which gives us a value to which the window should scroll. The last line actually scrolls the window to this value.

Here’s what everything looks like so far:

$(document).ready(function(){

	$('body').prepend('<div id="scrollbar-track"><div id="scrollbar"></div></div>');

	function scrollBar(){

		var viewportHeight = $(window).height();
		var docuHeight = $(document).height();

		var trackHeight = $('#scrollbar-track').height();

		var scrollbarHeight = (viewportHeight/docuHeight)*trackHeight;

		$('#scrollbar').height(scrollbarHeight);

		$('#scrollbar').draggable({
			axis: 'y',
			containment: 'parent',
			drag: function() {
				var scrollbarTop = parseInt($(this).css('top'));

				var scrollTopNew = (scrollbarTop/(trackHeight))*docuHeight;

				$(window).scrollTop(scrollTopNew);

			}
		});
	}
});

Now, we can initialize the function so that the code actually happens.

function scrollBar(){
//Code in here...
}

scrollBar();

At this point, dragging the scroll bar should result in the page scrolling around. The last thing we need to do is make the mousewheel/touchpad work. We’ll do this by using the “mousewheel” script.

$("body").bind("mousewheel", function (event, delta) {

	var scrollTop = $(window).scrollTop();
	var scrollTopNew = scrollTop - (delta * 40);

	$(window).scrollTop(scrollTopNew);

	var scrollbarTop = ($(window).scrollTop()/docuHeight)*trackHeight;

	$('#scrollbar').css({
		top: scrollbarTop
	});
});

This code is just after the “draggable” scrollbar code. Here, we bind a “mousewheel” event to the body, so whenver the mousewheel is moved, the code inside is executed.

The first variable, “scrollTop”, is how far the window has already scrolled. The next one, “scrollTopNew”, is where the window should now scroll to. It is determined by taking the current “scrollTop”, and using teh “delta” variable. The “delta” variable is a number, “1″ or “-1″. It is “-1″ if the user just scrolled down, and “+1″ if the user scrolled up. This number is multiplied by “30″, so when the user moves their mouse wheel down once, the page scrolls down by 30 pixels. This new value is then applied to the window’s “scrollTop” by using the “scrollTop” function. “scrollbarTop” is where the scrollbar should be as a result of the user’s mouse wheel or touchpad scrolling. It takes the current scrollTop divides it by the document height to get the ratio, and multiplies the ratio by the trackHeight so that the scrollbar is in the right position. The scrollbar is then given a top of “scrollbarTop”.

This code should work well, but it doesn’t work when the user resizes their browser window. We can fix this by using the following code:

$(window).resize(function(){
	scrollBar();
});

This way, the function is re-executed whenever the window is resized.

Here’s what all the javascript should look like:

$(document).ready(function(){

	$('body').prepend('<div id="scrollbar-track"><div id="scrollbar"></div></div>');

	function scrollBar(){

		var viewportHeight = $(window).height();
		var docuHeight = $(document).height();

		var trackHeight = $('#scrollbar-track').height();

		var scrollbarHeight = (viewportHeight/docuHeight)*trackHeight;

		$('#scrollbar').height(scrollbarHeight);

		$('#scrollbar').draggable({
			axis: 'y',
			containment: 'parent',
			drag: function() {
				var scrollbarTop = parseInt($(this).css('top'));

				var scrollTopNew = (scrollbarTop/(trackHeight))*docuHeight;

				$(window).scrollTop(scrollTopNew);

			}
		});

		$("body").bind("mousewheel", function (event, delta) {

			var scrollTop = $(window).scrollTop();
			var scrollTopNew = scrollTop - (delta * 40);

			$(window).scrollTop(scrollTopNew);

			var scrollbarTop = ($(window).scrollTop()/docuHeight)*trackHeight;

			$('#scrollbar').css({
				top: scrollbarTop
			});
		});

	}

	scrollBar();

	$(window).resize(function(){
		scrollBar();
	});

});

That’s it for this tutorial – I hope you enjoyed it and learned something new. If you have any questions or comments, post them below and I’ll do my best to answer.

  • Jon

    Interesting stuff. I’ve run the demo and whilst it works (very well) in Chrome and FireFox, in IE(9), both the scrollbar and the scrollwheel functionality are missing. Is this a shortcoming of IE, or should it work in all modern browsers?

    • Alexandre Smirnov

      Hello Jon,

      It seems that I accidentally put up a slightly older version of the code onto the demo page.  The tutorial code works perfectly, and now the demo page does as well.  Thanks for spotting the error!

  • mike

    I searched for a jquery custom scrollbar for a lot of time, and every time it seemed to have some sort of glitch, or i couldn’t make it work.
    This is one of the best explained and straightforward tutorials i’ve come across. I did it in les the 5 minutes. Thanx a lot man, you saved my day. 

    • Alexandre Smirnov

      I’m glad I helped :)

  • Szymon

    Is there any way to disable/hide scrollbar
    if(something){
    disablescroll
    }

    • John Motyl Jr

      What about using $.remove( ) on the created element and unbinding?

  • Piri

    Thx a lot, but is it possible to have this scrollbar inside a DIV, and have multiple scrollbars on one screen for different divs?

    Thx for your help

  • EricPorter

    Wonderful tool. Thanks a lot.

    My one caveat is that I have a one page site and the nav jumps you around the page. This custom scrollbar doesn’t follow the new positioning. It just stays in place until dragged which then jerks the viewport back to where the scrollbar was.

    Got any ideas?

  • Charles

    Hi! Looks cool but found a bug. When holding ctrl and scrolling (zooming in out) in _at least_ Firefox, the scrollbar moves to the side. When resetting the zoom level to zero, the scrollbar still appears outside window-frame. You should have a look at it..//C

    • Alexandre Smirnov

      I’ve reproduced the error, but it seems it’s a Firefox-only thing. It works fine in Chrome. Using the element inspector also doesn’t yield anything useful – it’s as if the right-hand border of the content on the page was outside of the browser window, and I don’t know how that could be fixed with JS. Thanks for the heads-up, though!

      • Charles

        Without digging too deep: a simple solution to this would be to measure the total height of content (html, body, div, whatever) and compare it to window.height. If window.height is larger than content.height, just remove the scrollbar, othervise “re-install” scrollbar and make it visible. Quite simple and should take care of things! :)

        • Alexandre Smirnov

          Yep, that seems like a pretty good way to fix it :)

          • Charles

            :) keep up the good work!