Akxl Labs C# ASP.NET Articles and Tutorials Akxl Labs Web Apps and Tools for Your Website

Scrollbars Made From JavaScript and CSS

Tags tagged as   Code: CSS, JavaScript, Web
An HTML/JavaScript/CSS based scrollbar that provides a more powerful, style-able, and smaller alternative to regular scrollbars. Dragging and the mouse wheel are both supported.

Posted March 29, 2007    Viewed 4176 times    Add to DiggAdd to del.icio.usAdd to FURLAdd to RedditAdd to YahooAdd to BlinklistAdd to GoogleAdd to ma.gnoliaAdd to ShadowsAdd to Technorati

Overview

This article presents the source code for a scrollbar created with HTML, JavaScript, and CSS.

This post was updated 4-15-2007 with a new version that supports the scroll wheel.

A purely JavaScript/CSS scrollbar has many advantages over a browser-generated scrollbar. It can be placed on any element, can be styled in a reliable, cross-browser compatible way with CSS and images, and can be made smaller or larger as the website design requires. The scrollbar can also be placed anywhere on the page, so it can be on either side of the content, or separated from the content by a margin. This affords many design possibilities, and allows the creation of smaller, subtler scrollbars for use in places where ordinary scrollbars might be inappropriate or attention-grabbing.

This script supports the five standard ways to manipulate content with a scrollbar:
  • Clicking on the up or down arrows moves the content by a fixed distance.
  • Holding down the mouse over the up or down arrows repeats the click action continuously.
  • Clicking on the scrollbar track moves the content by a fixed distance equal to twice the distance moved when clicking an arrow. The direction of movement is determined by whether you are above or below the gripper.
  • Dragging the gripper up or down moves the content up or down. The distance moved is equal to the percentage of the track height over which the gripper was moved multiplied by the content height.
  • Using the mouse scroll wheel while over the scrollable area scrolls the content.
The code is designed to support multiple scrollbars on a single page.

Articles and downloads sponsored by:
Thanks! Amazon commissions help me pay for textbooks.

Demonstration

Here is a quick demonstration of the scrollbar in action. I also use these scrollbars in several places around my website.

Scroll Up
Scroll Down
Akxl Labs
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nunc pharetra. Nullam aliquam, lorem et blandit vestibulum, lacus purus convallis tellus, quis vehicula nibh dolor a mi. Sed in ligula. Nullam malesuada volutpat tellus. Proin eros lacus, faucibus non, pretium in, cursus quis, elit. Sed turpis leo, iaculis et, dignissim a, posuere ut, magna. Quisque vel lectus. Morbi libero. Phasellus placerat diam vitae mi porttitor vulputate. Curabitur vitae metus eget elit tempor molestie. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos. Integer eu mi. Nam id lectus. Aenean non massa ac felis ornare ullamcorper. Cras sed nulla. Vestibulum nulla nulla, malesuada nec, tincidunt sed, dictum a, purus. Nulla vulputate, est eget mollis tempor, est diam lacinia nunc, et feugiat leo est ac odio. Donec tincidunt.

Maecenas egestas, purus sed pharetra ornare, neque odio congue metus, non bibendum felis massa ac augue. Ut in orci a est imperdiet facilisis. Vestibulum vel tellus eget enim gravida pellentesque. Sed faucibus mi vel purus. Nullam a arcu euismod nibh feugiat vehicula. Nulla facilisi. Phasellus nec mi. Sed eros ligula, venenatis feugiat, accumsan eu, cursus sed, nisl. Sed eu nisi. Quisque elit nisl, convallis quis, vestibulum ut, sollicitudin id, justo. Maecenas felis. Duis gravida, velit at rutrum tempus, arcu dui ullamcorper pede, varius eleifend urna nulla sagittis velit. Praesent volutpat erat egestas nunc. Donec feugiat tincidunt nibh. Mauris consectetuer posuere sem. Cras rhoncus sapien ac erat. Aliquam neque lectus, cursus non, gravida vitae, malesuada at, ipsum. Suspendisse viverra lorem id orci.

Ut pulvinar purus sed turpis. Sed magna sapien, fermentum ut, lobortis nec, accumsan non, ante. Fusce molestie ligula in augue. Suspendisse purus orci, suscipit vel, scelerisque a, tincidunt sit amet, ante. Sed placerat orci. Nulla semper dolor sit amet diam. Integer mauris. Suspendisse eget ipsum. Integer convallis mauris in arcu. Duis quis tellus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Maecenas ultricies consequat elit. Maecenas vitae nibh a augue laoreet consequat. Nullam nec augue. Nam dapibus. Aliquam erat volutpat.

Curabitur justo leo, cursus non, auctor at, venenatis sed, metus. Aenean tempus, diam at tempus imperdiet, est mauris pharetra quam, sed pretium est metus suscipit massa. Integer venenatis. Nunc nec eros. Aenean volutpat egestas orci. Cras bibendum velit vel est. In aliquet urna et libero. Suspendisse potenti. Suspendisse enim sapien, lacinia in, condimentum ac, dictum ut, felis. Aliquam sodales fringilla eros. Praesent euismod. Nam tortor sapien, facilisis quis, venenatis ac, imperdiet nec, nisl. Nulla facilisi. Pellentesque eleifend nibh a mi. Sed velit. Curabitur eu orci. Sed urna. Quisque sollicitudin, sem sed sollicitudin iaculis, orci ipsum rhoncus lacus, sed lacinia ligula tellus eu neque. Proin porta fermentum velit. Vestibulum dictum ligula sit amet nunc.


Download

Download the source code and examples:
AkxlJavaScriptScrollbar.zip (6K)

There are several files in the download:
  • A sample HTML page using the scrollbar
  • A CSS file containing the style information for the scrollbar
  • The JavaScript file that handles the scrollbar actions
  • Image files for the scrollbar look and feel
Each file is explained in detail below.

How It Works

The HTML used to create the scrollbar is below. There are a couple of important things to note about this HTML:
  • To allow multiple scrollbars on a page, each scrollbar needs a unique name. This scrollbar is called DemoScroller. To change the scrollbar's name, you need to replace all occurrences of DemoScroller with the new scrollbar's name.
  • The div tag called DemoScroller_ScrollingArea contains the scrollable content.
  • The div tag called DemoScroller_Gripper is the scrollbar gripper. Any content inside this tag appears inside the gripper, so you can add code to this div to affect the look of the gripper. The example code inside this tag adds the double border and the ridges to the gripper.

Scrollbar HTML

1 <div id="DemoScroller_Container" onmouseover="SetScrollAreaActive('DemoScroller');" onmouseout="SetScrollAreaInactive('DemoScroller');"> 2 <div id="DemoScroller_ScrollBar"> 3 <div id="DemoScroller_UpArrow" onmousedown="StartScrollUp('DemoScroller');" onmouseup="StopScroll();"><img src="/images/scrollbar/up.gif" width="10" height="7" alt="Scroll Up" style="position: absolute; top: 0px; left: 0px;" /></div> 4 <div id="DemoScroller_GripperContainer" onclick="ScrollBarTrackClick('DemoScroller', event);"> 5 <div id="DemoScroller_Gripper" onmousedown="ScrollBarDragStart(event, this.id);"> 6 <table cellpadding="0" cellspacing="0" style="height: 100%; border: 1px solid #BABABA;"><tr><td height="100%"> 7 <table cellpadding="0" cellspacing="0" style="height: 100%; border: 1px solid #FFFFFF;"><tr><td height="100%"> 8 <table cellpadding="0" cellspacing="0" style="height: 100%; width: 6px; background-image: url('/images/scrollbar/gripper_innerbackground.gif'); background-repeat: repeat-y; background-position: top left; text-align: center;"> 9 <tr><td height="100%" valign="middle"><img src="/images/scrollbar/gripper_notches.gif" width="4" height="11" alt="" /></td></tr> 10 </table> 11 </td></tr></table> 12 </td></tr></table> 13 </div> 14 </div> 15 <div id="DemoScroller_DownArrow" onmousedown="StartScrollDown('DemoScroller');" onmouseup="StopScroll();"><img src="/images/scrollbar/down.gif" width="10" height="7" alt="Scroll Down" style="position: absolute; top: 0px; left: 0px;" /></div> 16 </div> 17 18 <div id="DemoScroller_Content"> 19 <div id="DemoScroller_ScrollingArea"> 20 21 <img src="/images/akxllabs_dark.gif" width="164" height="50" alt="Akxl Labs" align="left" hspace="3" vspace="3" /> 22 23 Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nunc pharetra. Nullam aliquam, lorem et blandit vestibulum, lacus purus convallis tellus, quis vehicula nibh dolor a mi. Sed in ligula. Nullam malesuada volutpat tellus. Proin eros lacus, faucibus non, pretium in, cursus quis, elit. Sed turpis leo, iaculis et, dignissim a, posuere ut, magna. Quisque vel lectus. Morbi libero. Phasellus placerat diam vitae mi porttitor vulputate. Curabitur vitae metus eget elit tempor molestie. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos. Integer eu mi. Nam id lectus. Aenean non massa ac felis ornare ullamcorper. Cras sed nulla. Vestibulum nulla nulla, malesuada nec, tincidunt sed, dictum a, purus. Nulla vulputate, est eget mollis tempor, est diam lacinia nunc, et feugiat leo est ac odio. Donec tincidunt. 24 <br /><br /> 25 26 Maecenas egestas, purus sed pharetra ornare, neque odio congue metus, non bibendum felis massa ac augue. Ut in orci a est imperdiet facilisis. Vestibulum vel tellus eget enim gravida pellentesque. Sed faucibus mi vel purus. Nullam a arcu euismod nibh feugiat vehicula. Nulla facilisi. Phasellus nec mi. Sed eros ligula, venenatis feugiat, accumsan eu, cursus sed, nisl. Sed eu nisi. Quisque elit nisl, convallis quis, vestibulum ut, sollicitudin id, justo. Maecenas felis. Duis gravida, velit at rutrum tempus, arcu dui ullamcorper pede, varius eleifend urna nulla sagittis velit. Praesent volutpat erat egestas nunc. Donec feugiat tincidunt nibh. Mauris consectetuer posuere sem. Cras rhoncus sapien ac erat. Aliquam neque lectus, cursus non, gravida vitae, malesuada at, ipsum. Suspendisse viverra lorem id orci. 27 <br /><br /> 28 29 Ut pulvinar purus sed turpis. Sed magna sapien, fermentum ut, lobortis nec, accumsan non, ante. Fusce molestie ligula in augue. Suspendisse purus orci, suscipit vel, scelerisque a, tincidunt sit amet, ante. Sed placerat orci. Nulla semper dolor sit amet diam. Integer mauris. Suspendisse eget ipsum. Integer convallis mauris in arcu. Duis quis tellus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Maecenas ultricies consequat elit. Maecenas vitae nibh a augue laoreet consequat. Nullam nec augue. Nam dapibus. Aliquam erat volutpat. 30 <br /><br /> 31 32 Curabitur justo leo, cursus non, auctor at, venenatis sed, metus. Aenean tempus, diam at tempus imperdiet, est mauris pharetra quam, sed pretium est metus suscipit massa. Integer venenatis. Nunc nec eros. Aenean volutpat egestas orci. Cras bibendum velit vel est. In aliquet urna et libero. Suspendisse potenti. Suspendisse enim sapien, lacinia in, condimentum ac, dictum ut, felis. Aliquam sodales fringilla eros. Praesent euismod. Nam tortor sapien, facilisis quis, venenatis ac, imperdiet nec, nisl. Nulla facilisi. Pellentesque eleifend nibh a mi. Sed velit. Curabitur eu orci. Sed urna. Quisque sollicitudin, sem sed sollicitudin iaculis, orci ipsum rhoncus lacus, sed lacinia ligula tellus eu neque. Proin porta fermentum velit. Vestibulum dictum ligula sit amet nunc. 33 34 </div> 35 </div> 36 </div> 37 <br clear="all" /> 38 39 <script language="JavaScript" type="text/javascript"> 40 window.onload = function() { SetScrollbarHeight('DemoScroller'); }; 41 </script>

The scrollbar needs to use window.onload to set the height of the gripper based on the height of the content. If your page already uses window.onload for something else, you may want to try the WindowOnload script from Firtree to allow multiple functions to share window.onload. In that case, your code would use:
WindowOnload(function() { SetScrollbarHeight('DemoScroller'); });.

Each scrollbar needs a CSS file to specify the look and feel of the scrollbar, and the behavior of it's components. I recommend creating separate CSS files for each different scrollbar, so you can include them as needed. Again, note that the names of the CSS classes correspond to the scrollbar name. If you change the scrollbar name from DemoScroller, make sure the update the names here as well.

Scrollbar CSS

1 #DemoScroller_Container 2 { 3 height: 150px; 4 width: 400px; 5 position: relative; 6 } 7 8 #DemoScroller_Content 9 { 10 height: 150px; 11 width: 388px; 12 overflow: hidden; 13 position: relative; 14 float: left; 15 margin-right: 2px; 16 } 17 18 #DemoScroller_ScrollingArea 19 { 20 position: absolute; 21 top: 0px; 22 left: 0px; 23 width: 388px; 24 text-align: left; 25 } 26 27 #DemoScroller_ScrollBar 28 { 29 height: 150px; 30 width: 10px; 31 float: right; 32 position: relative; 33 } 34 35 #DemoScroller_UpArrow 36 { 37 height: 7px; 38 cursor: pointer; 39 cursor: hand; 40 text-align: center; 41 position: relative; 42 } 43 44 #DemoScroller_GripperContainer 45 { 46 height: 136px; 47 position: relative; 48 cursor: pointer; 49 cursor: hand; 50 background-image: url('/images/scrollbar/track_background.gif'); 51 background-repeat: repeat-y; 52 background-position: top left; 53 } 54 55 #DemoScroller_Gripper 56 { 57 position: absolute; 58 top: 0px; 59 left: 0px; 60 width: 10px; 61 height: 75px; 62 cursor: pointer; 63 cursor: hand; 64 } 65 66 #DemoScroller_DownArrow 67 { 68 height: 7px; 69 cursor: pointer; 70 cursor: hand; 71 text-align: center; 72 position: relative; 73 }

The scrollbar requires a good chunk of JavaScript. The portion of this script that provides the drag function to the gripper is based on Mike Hall's Generic Drag examples, with modifications to make objects draggable only within the bounds of a relatively positioned parent.

Scrollbar JavaScript

1 var scrollIncrement = 15; 2 3 var blockTrackClick = false; 4 var scrollInterval; 5 var scrollHoldInterval = 250; 6 var activeScrollArea = null; 7 var activeScrollResetTimer; 8 9 function SetScrollAreaActive(elem) 10 { 11 clearTimeout(activeScrollResetTimer); 12 activeScrollArea = elem; 13 } 14 15 function SetScrollAreaInactive(elem) 16 { 17 activeScrollResetTimer = setTimeout("activeScrollArea = null", 100); 18 } 19 20 function StartScrollUp(elem) 21 { 22 ScrollUp(elem); 23 scrollInterval = setInterval("ScrollUp('" + elem + "');", scrollHoldInterval); 24 } 25 26 function StartScrollDown(elem) 27 { 28 ScrollDown(elem); 29 scrollInterval = setInterval("ScrollDown('" + elem + "');", scrollHoldInterval); 30 } 31 32 function StopScroll() 33 { 34 clearInterval(scrollInterval); 35 } 36 37 function ScrollUp(elem) 38 { 39 var scrollPos = GetTopScrollAmount(elem) + scrollIncrement; 40 if (scrollPos > 0) scrollPos = 0; 41 document.getElementById(elem + "_ScrollingArea").style.top = scrollPos + "px"; 42 43 SetScrollBarPercentage(elem, GetScrollPercentage(elem)); 44 } 45 46 function ScrollDown(elem) 47 { 48 var scrollPos = GetTopScrollAmount(elem) - scrollIncrement; 49 scrollHeight = GetScrollHeight(elem); 50 if (scrollPos < (-1 * scrollHeight)) scrollPos = (-1 * scrollHeight); 51 document.getElementById(elem + "_ScrollingArea").style.top = scrollPos + "px"; 52 53 SetScrollBarPercentage(elem, GetScrollPercentage(elem)); 54 } 55 56 function ScrollBarTrackClick(elem, event) 57 { 58 if (blockTrackClick) return; 59 60 var y, yMove; 61 62 if (browser.isIE) 63 y = window.event.clientY + document.documentElement.scrollTop + document.body.scrollTop; 64 if (browser.isNS) 65 y = event.clientY + window.scrollY; 66 67 if (y > GetPosY(document.getElementById(elem + "_Gripper"))) 68 { 69 ScrollDown(elem); 70 ScrollDown(elem); 71 } 72 else 73 { 74 ScrollUp(elem); 75 ScrollUp(elem); 76 } 77 } 78 79 function GetTopScrollAmount(elem) 80 { 81 return GetPosY(document.getElementById(elem + "_ScrollingArea")) - GetPosY(document.getElementById(elem + "_Content")); 82 } 83 84 function GetScrollHeight(elem) 85 { 86 return document.getElementById(elem + "_ScrollingArea").offsetHeight - document.getElementById(elem + "_Content").offsetHeight; 87 } 88 89 function GetTrackDistance(elem) 90 { 91 return document.getElementById(elem + "_GripperContainer").offsetHeight - document.getElementById(elem + "_Gripper").offsetHeight; 92 } 93 94 function GetGripperPosition(elem) 95 { 96 return GetPosY(document.getElementById(elem + "_Gripper")) - GetPosY(document.getElementById(elem + "_GripperContainer")); 97 } 98 99 function GetScrollBarPercentage(elem) 100 { 101 var topOffset = GetGripperPosition(elem); 102 var trackDistance = GetTrackDistance(elem); 103 104 return topOffset / trackDistance; 105 } 106 107 function SetScrollBarPercentage(elem, percentage) 108 { 109 GetTrackDistance(elem) 110 111 document.getElementById(elem + "_Gripper").style.top = Math.floor(GetTrackDistance(elem) * percentage) + "px"; 112 } 113 114 function GetScrollPercentage(elem) 115 { 116 return -1 * (GetTopScrollAmount(elem) / GetScrollHeight(elem)); 117 } 118 119 function SetScrollPercentage(elem, percentage) 120 { 121 document.getElementById(elem + "_ScrollingArea").style.top = (-1 * Math.floor(GetScrollHeight(elem) * percentage)) + "px"; 122 } 123 124 function SetScrollbarHeight(elem) 125 { 126 var visiblePercentage = document.getElementById(elem + "_Content").offsetHeight / document.getElementById(elem + "_ScrollingArea").offsetHeight; 127 128 if (visiblePercentage > 1) 129 visiblePercentage = 1; 130 131 var gripperHeight = Math.floor(document.getElementById(elem + "_GripperContainer").offsetHeight * visiblePercentage); 132 133 if (gripperHeight < 20) 134 gripperHeight = 20; 135 136 document.getElementById(elem + "_Gripper").style.height = gripperHeight + "px"; 137 } 138 139 function GetPosX(obj) 140 { 141 var curleft = 0; 142 if (obj.offsetParent) 143 { 144 while (obj.offsetParent) 145 { 146 curleft += obj.offsetLeft 147 obj = obj.offsetParent; 148 } 149 } 150 else if (obj.x) 151 curleft += obj.x; 152 153 return curleft; 154 } 155 156 function GetPosY(obj) 157 { 158 var curtop = 0; 159 if (obj.offsetParent) 160 { 161 while (obj.offsetParent) 162 { 163 curtop += obj.offsetTop 164 obj = obj.offsetParent; 165 } 166 } 167 else if (obj.y) 168 curtop += obj.y; 169 170 return curtop; 171 } 172 173 //***************************************************************************** 174 // Javascript Mouse Wheel handling code - based on an article by: 175 // http://adomas.org/javascript-mouse-wheel/ 176 //***************************************************************************** 177 178 function handleMouseWheelScroll(scrollDelta) 179 { 180 var safety = 0; 181 182 if (scrollDelta < 0) 183 { 184 for (var x=0; x > scrollDelta && safety < 3; x--) 185 { 186 ScrollDown(activeScrollArea); 187 safety++; 188 } 189 } 190 191 if (scrollDelta > 0) 192 { 193 for (var x=0; x < scrollDelta && safety < 3; x++) 194 { 195 ScrollUp(activeScrollArea); 196 safety++; 197 } 198 } 199 200 } 201 202 function mouseWheelActive(event) 203 { 204 if (activeScrollArea == null) 205 return; 206 207 var delta = 0; 208 if (!event) event = window.event; 209 if (event.wheelDelta) { 210 delta = event.wheelDelta/120; 211 if (window.opera) delta = -delta; 212 } else if (event.detail) { 213 delta = -event.detail/4; 214 } 215 if (delta) 216 handleMouseWheelScroll(delta); 217 if (event.preventDefault) 218 event.preventDefault(); 219 event.returnValue = false; 220 } 221 222 if (window.addEventListener) 223 window.addEventListener('DOMMouseScroll', mouseWheelActive, false); 224 window.onmousewheel = document.onmousewheel = mouseWheelActive; 225 226 //***************************************************************************** 227 // Do not remove this notice. 228 // 229 // Copyright 2001 by Mike Hall. 230 // Modified to bound allowable drag area to relative parent by Adam Hamilton. 231 //***************************************************************************** 232 233 // Determine browser and version. 234 235 function Browser() { 236 237 var ua, s, i; 238 239 this.isIE = false; 240 this.isNS = false; 241 this.version = null; 242 243 ua = navigator.userAgent; 244 245 s = "MSIE"; 246 if ((i = ua.indexOf(s)) >= 0) { 247 this.isIE = true; 248 this.version = parseFloat(ua.substr(i + s.length)); 249 return; 250 } 251 252 s = "Netscape6/"; 253 if ((i = ua.indexOf(s)) >= 0) { 254 this.isNS = true; 255 this.version = parseFloat(ua.substr(i + s.length)); 256 return; 257 } 258 259 // Treat any other "Gecko" browser as NS 6.1. 260 261 s = "Gecko"; 262 if ((i = ua.indexOf(s)) >= 0) { 263 this.isNS = true; 264 this.version = 6.1; 265 return; 266 } 267 } 268 269 var browser = new Browser(); 270 271 // Global object to hold drag information. 272 273 var dragObj = new Object(); 274 dragObj.zIndex = 0; 275 276 function ScrollBarDragStart(event, id) { 277 278 blockTrackClick = true; 279 280 var el; 281 var x, y; 282 283 // If an element id was given, find it. Otherwise use the element being 284 // clicked on. 285 286 if (id) 287 dragObj.elNode = document.getElementById(id); 288 else { 289 if (browser.isIE) 290 dragObj.elNode = window.event.srcElement; 291 if (browser.isNS) 292 dragObj.elNode = event.target; 293 294 // If this is a text node, use its parent element. 295 296 if (dragObj.elNode.nodeType == 3) 297 dragObj.elNode = dragObj.elNode.parentNode; 298 } 299 300 // Get cursor position with respect to the page. 301 302 if (browser.isIE) { 303 x = window.event.clientX + document.documentElement.scrollLeft 304 + document.body.scrollLeft; 305 y = window.event.clientY + document.documentElement.scrollTop 306 + document.body.scrollTop; 307 } 308 if (browser.isNS) { 309 x = event.clientX + window.scrollX; 310 y = event.clientY + window.scrollY; 311 } 312 313 // Save starting positions of cursor and element. 314 315 dragObj.cursorStartX = x; 316 dragObj.cursorStartY = y; 317 dragObj.elStartLeft = parseInt(dragObj.elNode.style.left, 10); 318 dragObj.elStartTop = parseInt(dragObj.elNode.style.top, 10); 319 320 if (isNaN(dragObj.elStartLeft)) dragObj.elStartLeft = 0; 321 if (isNaN(dragObj.elStartTop)) dragObj.elStartTop = 0; 322 323 // Update element's z-index. 324 325 dragObj.elNode.style.zIndex = ++dragObj.zIndex; 326 327 // Capture mousemove and mouseup events on the page. 328 329 if (browser.isIE) { 330 document.attachEvent("onmousemove", ScrollBarDragGo); 331 document.attachEvent("onmouseup", ScrollBarDragStop); 332 window.event.cancelBubble = true; 333 window.event.returnValue = false; 334 } 335 if (browser.isNS) { 336 document.addEventListener("mousemove", ScrollBarDragGo, true); 337 document.addEventListener("mouseup", ScrollBarDragStop, true); 338 event.preventDefault(); 339 } 340 } 341 342 function ScrollBarDragGo(event) { 343 344 var x, y; 345 346 // Get cursor position with respect to the page. 347 348 if (browser.isIE) { 349 x = window.event.clientX + document.documentElement.scrollLeft 350 + document.body.scrollLeft; 351 y = window.event.clientY + document.documentElement.scrollTop 352 + document.body.scrollTop; 353 } 354 if (browser.isNS) { 355 x = event.clientX + window.scrollX; 356 y = event.clientY + window.scrollY; 357 } 358 359 // Bound the movement of the element to within it's parent 360 var ctx, cty, mtx, mty; //, cbx, cby; 361 362 ctx = dragObj.elStartLeft + x - dragObj.cursorStartX; 363 cty = dragObj.elStartTop + y - dragObj.cursorStartY; 364 365 mtx = dragObj.elNode.parentNode.offsetWidth - dragObj.elNode.offsetWidth; 366 mty = dragObj.elNode.parentNode.offsetHeight - dragObj.elNode.offsetHeight; 367 368 if (ctx > mtx) ctx = mtx; 369 if (ctx < 0) ctx = 0; 370 371 if (cty > mty) cty = mty; 372 if (cty < 0) cty = 0; 373 374 // Move drag element by the same amount the cursor has moved. 375 376 dragObj.elNode.style.left = (ctx) + "px"; 377 dragObj.elNode.style.top = (cty) + "px"; 378 379 if (browser.isIE) { 380 window.event.cancelBubble = true; 381 window.event.returnValue = false; 382 } 383 if (browser.isNS) 384 event.preventDefault(); 385 386 var elemName = dragObj.elNode.id.split('_')[0]; 387 SetScrollPercentage(elemName, GetScrollBarPercentage(elemName)); 388 } 389 390 function ScrollBarDragStop(event) { 391 392 setTimeout("blockTrackClick = false;", 100); 393 394 // Stop capturing mousemove and mouseup events. 395 396 if (browser.isIE) { 397 document.detachEvent("onmousemove", ScrollBarDragGo); 398 document.detachEvent("onmouseup", ScrollBarDragStop); 399 } 400 if (browser.isNS) { 401 document.removeEventListener("mousemove", ScrollBarDragGo, true); 402 document.removeEventListener("mouseup", ScrollBarDragStop, true); 403 } 404 }

To use the scrollbars on a web page, you need to include the CSS file(s) and the JavaScript file for the scrollbars in the section of the page. Change the file locations here to match the ones used on your website.

1 <link rel="stylesheet" type="text/css" href="/css/jsscroll.css" /> 2 <script language="JavaScript" type="text/javascript" 3 src="/javascript/jsscroll.js"></script>


Credits and Resources


Comments & Feedback


nikita evgenevich says:
Sunday, April 08, 2007 @ 5:01 PM
shame, the example doesn't work with wheel scrolling while hovering over it.... that's the only thing stopping me from trying this out....
Adam says:
Sunday, April 08, 2007 @ 6:56 PM
I can't think of a way to get any information about the scroll wheel in JavaScript. I'll check into this a little further; if anyone knows how this might be done please post a link.
Adam says:
Sunday, April 15, 2007 @ 8:35 PM
As it turns out, there is some great work out there on mouse wheel interaction in JavaScript. With a little modification to some existing examples, I was able to create a mouse wheel handler that overrides the default mouse wheel behavior only when over a JavaScript Scrollbar area, and scrolls that JavaScript scrollbar whenever the mouse wheel is moved. I updated this article to use scroll wheel interaction now.
Anonymous says:
Sunday, August 12, 2007 @ 11:29 AM
Hey Adam,

Great work, I was looking for a way
Jon Giles says:
Sunday, August 12, 2007 @ 11:30 AM
Sorry miss post above: Great solution, in a reasonably neat solution plus the mouse wheel functionality is great. Have you considered implementing keyboard functionality? The Iframes you use for code above use this (in IE and FF) but you JS doesn't. I'm not a JS wiz so don't really know how to go about it?
Cheers,
Jon.
e says:
Saturday, November 10, 2007 @ 5:25 PM
It seems to do some rather weird things in Opera 9. The scroll bar thumb changes size and it's not draggable (though the up and down buttons work). Probably horrible for accessibility too, though it's quite clever.
Adam says:
Sunday, December 23, 2007 @ 9:49 PM
Opera 9? Who cares about Opera 9?

Accessibility is actually quite good though, as this scrollbar was actually designed for search engines, which view the page in plain text.

Search engines determine the 'top-tier' pages in a website based on the number of internal links to them. For example, a page on the navigation menu of a website has a lot of internal links, and so search engines know it is an important page on the site.

I created this script to allow me to cram links to each of my articles into my narrow little navigation menu, so Google would know they were the focus of my site. Google sees all of my articles linked on the menu, while users only see the little scrollable area, and it all happens in a way that doesn't violate Google's terms because none of the links are 'hidden' in a link-spamming way.

To do this, the scrollbars were designed in a way that degrades to nothing more than stacked div tags if you disable JavaScript. Just check out the HTML code to see that the scrollable area is just a div, nested in more divs, until CSS and JavaScript are applied.
Rob says:
Monday, August 24, 2009 @ 12:03 AM
There is an issue with IE6, as the scrollbar doesn't show the full length of the box.
Any fix for this?
Juehua says:
Thursday, November 26, 2009 @ 1:03 AM
Good job Bro!
Leave this field blank:
Comment on this Entry
This work is licensed under a Creative Commons Attribution 3.0 United States License.
Please link to this article in your source code comments if you use this content.

Labs

Blog

The blog has moved.
Non-technical articles are now on a seperate site.
Contact me for the new address.

Apps

Real-Time Coffee Counter
add it to your website!
Golden Ratio Visualizer
a tool for design

Coffee Counter

Current Count:
Akxl Coffee Meter
Current Coffee:
 Peet's Malawi Songwe River

The Real-Time Coffee Meter is a free Website App from Akxl Labs. Text-only and badge versions available.