Styling Scrollable Areas

Chris Coyier //

The scrollbars on browser windows are not styled by the website itself, or even generally by the browser. They come from the operating system itself.

The desire to customize the style of these scrollbars is strong. When you are starting out, it feels like something you should be able to do with CSS. Complicating the issue, if you search around for CSS to change/customize scrollbars, you'll probably find it. The problem is that in IE 5.5, there was proprietary browser extensions to change the look of your scrollbars with attributes like "scrollbar-face-color". IE 5.5 is long gone, and the concept of allowing that control is CSS is gone with it.

There are situations though, where you will strongly wish you had control over the look of a scrollbar. For instance, when the scrollbar isn't for the entire browser window. You have a small section on your page that you need to control the height of, but contains content which overflows the container. You may set the overflow of that container to "auto", and get your default scrollbar. Depending on the design of the site, this scrollbar may look awkward and not at all desirable.

Fortunately, we can harness the amazing powers of JavaScript to solve this problem and give us complete design control over our scrollbars again. The basic theory is that we wrap the scrollable area in a new element with HIDDEN overflow, then we remove the overflow from the inside element letting it be as tall as it needs to be. Then we add a scrollbar of our own devise and watch for mouse events on it. As we drag it up and down, it adjusts the relative top value of the inside container, replicating perfectly the scrolling.

To make things easier on ourselves, we'll use an already-existing jQuery plugin: jScrollPane.

View Demo Download Files

 

Tested and it working in Fx3, Safari 4, IE 6. Opera 9.52 was working, but strangely triggered a regular body scrollbar in some cases.

Step 1: The Markup

<body>

	<div id="page-wrap">

	<div class="scroll-pane">
 		
	</div>
	
	<img src="images/bottomshadow.png" alt="" class="bottomshadow" />
	
	</div>

</body>

The only reason we have a pagewrap here is because we are centering our little scrollable area. Since the plugin will wrap that div with a class of "scroll-pane" in another div, any centering we apply to it will just center it inside that new wrap, not to the body itself. So rather than mess with that, we'll just wrap it again in a page-wrap to do our basic positioning and centering. We can also apply relative positioning to that wrap, which will allow us to place the shadow graphic inside it and absolutely position it exactly where we want it on the bottom.

Step 2: The CSS

*					{ margin: 0; padding: 0; }
body				{ font-size: 12px; line-height: 30px; font-family: Georgia, serif; 
					  background: url(../images/clown.jpg) top left no-repeat #fbfbfb; }

#page-wrap			{ width: 244px; margin: 50px auto; position: relative; }

.scroll-pane 		{ width: 234px; overflow: auto; padding-right: 10px; height: 400px; }

.bottomshadow 		{ position: absolute; top: 375px; left: -47px; z-index: 9999; }

.jScrollPaneContainer 	{ position: relative; overflow: hidden; z-index: 1; }

.jScrollPaneTrack 		{ position: absolute; cursor: pointer; right: 0; top: 0; height: 100%;
						  background: url(../images/bar.jpg) top center repeat-y; padding: 3px; }

.jScrollPaneDrag	{ position: absolute; background: url(../images/ball.png) center center no-repeat;
					  cursor: pointer; overflow: hidden; }

We covered most of the theory here already. Of interest is the jScrollPaneTrack and jScrollPaneDrag. This is where you get you control over what the scrollbar and scroll handle look like. I've applied a rather ragged looking line as the track and a small ragged ball as the handle.

Step 3: Activating JavaScript

Typical plugin activation here. Include jQuery on your page, then the plugin, then call the plugins new function with the parameters you need. In our case, the ball is 12px wide, so we need to specify that when calling the function. That's just how this function rolls.

<script type="text/javascript" src="js/jquery-1.2.6.min.js"></script>
<script type="text/javascript" src="js/jScrollPane.js"></script>
<script type="text/javascript">
	$(function(){
		$('.scroll-pane').jScrollPane({
			scrollbarWidth: 12
		});
	});
</script>

Step 4: Considering Usability and Accessibility

When you remove the standard scrollbar in this manner, you are taking away consistency and convention from users. People become so used to user interface conventions like scrollbars that they might gloss right over your customized one not even recognizing it as a scrollbar. That is obviously a problem. You should be darn sure that your scrollbar strongly reads as a scrollbar if you want people to actually use it (the example in this article could be dramatically improved in this regard). I certainly don't worship Jakob Nielsen (especially his god-awful website), but he has a pretty good article on scrollbar standards and what works and what doesn't when it comes to custom ones.

Also be aware the standard scrollbars come with some accessibility built in that your new custom ones won't. Mostly, this plugin approach is solid. With JavaScript off, you'll just get regular scrollbars. With CSS off, you'll see all your content just fine. With both turned on, you'll get your snazzy new scrollbar, but you will lose the ability to scroll down that area using conventional methods (like the scrolling wheel on your mouse).

Just take all of this into consideration before going with a custom approach. I think it can be the right answer in many design situations where an operating system standard scrollbar can ruin a design.