Vertical scrollbar using jQuery UI slider

Wasted another morning messing about with the jQuery UI slider, trying to get it to work vertically rather than horizontally. Seems like quite a few others have been looking for the same thing, so here’s my attempt. I began by adapting the code on the jQuery UI site for a horizontal slider. This worked, but seemed unnecessarily complex, so I had another go, starting from the vertical slider code. The result is a lot cleaner.

The code assumes a single div with fixed height (#scroll-pane in my example) which contains an absolutely positioned div (#scroll-content) which contains the content for scrolling. I’ve positioned the scrollbar immediately to the right of #scroll-pane, but it can go anywhere you like. There’s a bit of calculation involved, and then the top value of #scroll-content is changed via the slider to make the content scroll up and down.

There’s a fundamental aspect of the way the vertical slider works which took me a little time to get my head round, and that’s that the slider as a default starts from zero at the bottom and increases upwards – which is the wrong way round for a vertical scroller, hence the need for a bit of extra calculation.

Here’s the css:

#scroll-pane { float:left;overflow: auto; width: 420px; height:300px;position:relative;border:1px solid gray;margin-left:50px;margin-bottom:25px;display:inline}
#scroll-content {position:absolute;top:0;left:0}
.scroll-content-item {background-color:#fcfcfc;color:#003366;width:100px;height:100px;float:left;margin:10px;font-size:3em;line-height:96px;text-align:center;border:1px solid gray;display:inline;}
#slider-wrap{float:left;background-color:lightgrey;height:300px;width:20px;border:1px solid gray;border-left:none;}
#slider-vertical{position:relative;height:100%}
.ui-slider-handle{width:20px;height:10px;margin:0 auto;background-color:darkgray;display:block;position:absolute}

and here’s the javascript:

$(function() {
//change the main div to overflow-hidden as we can use the slider now
$("#scroll-pane").css('overflow','hidden');

//calculate the height that the scrollbar handle should be
var difference = $("#scroll-content").height()-$("#scroll-pane").height();//eg it's 200px longer 
var proportion = difference / $("#scroll-content").height();//eg 200px/500px
var handleHeight = Math.round((1-proportion)*$("#scroll-pane").height());//set the proportional height - round it to make sure everything adds up correctly later on

//set up the slider 
$("#slider-vertical").slider({
orientation: "vertical",
range: "max",
min: 0,
max: 100,
value: 100,
slide: function(event, ui) {
var topValue = -((100-ui.value)*difference/100);
$("#scroll-content").css({top:topValue});//move the top up (negative value) by the percentage the slider has been moved times the difference in height
}
});

//set the handle height and bottom margin so the middle of the handle is in line with the slider
$(".ui-slider-handle").css({height:handleHeight,'margin-bottom':-0.5*handleHeight});

var origSliderHeight = $("#slider-vertical").height();//read the original slider height
var sliderHeight = origSliderHeight - handleHeight ;//the height through which the handle can move needs to be the original height minus the handle height
var sliderMargin =  (origSliderHeight - sliderHeight)*0.5;//so the slider needs to have both top and bottom margins equal to half the difference
$(".ui-slider").css({height:sliderHeight,'margin-top':sliderMargin});//set the slider height and margins

});

Here’s a demo page. I imagine most people want to use this with their own styling, so I’ve used some pretty minimal styling which is easily adaptable.

I’ve tested this in IE6, IE7, FF3.6, Safari 4, Chrome and Opera, and it seems to function correctly in all these.

Feel free to reuse the code and/or leave suggestions for improvement below.

Update 8 September 2010 – mouse and scrollbar synced correctly

Following Rob’s comment (#5 below) I’ve amended both the css and javascript to fix a problem where the mouse and scrollbar weren’t in sync. Both the code on this page and the demo are updated.

Update 4 August 2010 – mousewheel integration

Following Yves’ comment below I thought I’d have a go with adding mousewheel functionality as well. I used Brandon Aaron’s mousewheel plugin.

Then I’ve added the following additional javascript:

$("document").mousewheel(function(event, delta){

     var speed = 5;//set the speed of the scroll
     var sliderVal = $("#slider-vertical").slider("value");//read current value of the slider

     sliderVal += (delta*speed);//increment the current value

     $("#slider-vertical").slider("value", sliderVal);//and set the new value of the slider

     var topValue = -((100-sliderVal)*difference/100);//calculate the content top from the slider position

     if (topValue>0) topValue = 0;//stop the content scrolling down too much
     if (Math.abs(topValue)>difference) topValue = (-1)*difference;//stop the content scrolling up too much

     $("#scroll-content").css({top:topValue});//move the content to the new position

     event.preventDefault();//stop any default behaviour

});

I’ve kept this code separate from the rest so you can use it as required. It’s included in the demo page. The mousewheel works anywhere on the page on the demo – restrict the elements where the mousewheel activates the scroll as required.

Additional autocomplete add on

In response to the comment below, I’ve added jQuery UI Autocomplete integration here.

6 responses to “Vertical scrollbar using jQuery UI slider”

  1. Yves says:

    Thanks for the informative article. Mouse-wheel support would certainly be a great addition !

  2. Simon says:

    Thanks. You could try this plugin for the mousewheel.

    EDIT:Mousewheel support is now included on the demo.

  3. Dan says:

    I’ve begun using this to try it out; I was thinking exactly the same… editing the horizontal and the nightmare began ensuing. This is a great solution to an obvious problem, well done.

    I’m intrigued as to whether ‘auto-complete’ type functionality can be factored into this at all? I’ve got a lot of options in my slider (it’s used to navigate through a user’s assets) and quick finding what you want would be a great addition. i.e. moving slider to a position with an event?

    Great to hear your thoughts; and if its just silly.

  4. Simon says:

    Hi Dan

    Interesting suggestion – I’ve added this functionality to the basic slider here.

  5. Rob says:

    Great adaptation! Slight problem though, in that the drag bar does not track the exact location of the mouse. I saw that on the demo page under Chrome and IE 8.

  6. Simon says:

    Rob – you’re right – I’ve noticed that myself. It’s now fixed.

Useful? Interesting? Leave me a comment