Custom scrollbars – cross-browser solution

Tutorials

Today we will create custom stylized scrollbars for our website(s). We will use pure javascript to build own scrollbar. So this will really cross browser solution. We can use keys Up/Down keyboard keys to scroll content, mouse roller, drag and drop of scroller, etc (all what should have normal scrollbar).

In beginning – download our package and check demo:

Live Demo

[sociallocker]

download in package

[/sociallocker]


Lets start coding !


Step 1. HTML

As usual, we start with the HTML. This is source code of our sample:

index.html

001 <html>
002 <head>
003     <link rel="stylesheet" href="css/main.css" type="text/css" />
004     <script src="js/main.js"></script>
005 </head>
006 <body>
007     <div class="example">
008         <div id="main_content" style="height:90%;">
009             <div class="parent">
010             <h2>Arkady and Boris Strugatsky. Poor cruel folk</h2>
011                 <img src="images/engl_amal02.gif" alt="" />
012                 <div>The King sat naked. Like a foolish pauper on the street, he sat leaning
013                 against  a  cold  wall, drawing in his blue, goose-bumped legs. He shivered,
014                 with his eyes closed, he listened, but everything was quiet.</div>
015                 <div>He awoke at midnight from a nightmare and immediatelly understood  that
016                 he  was  finished.  Some  one  weezed and writhed by the door of the bedroom
017                 suite, he heard footsteps, metalic jingling and  drunken  mummbling  of  His
018                 Highness,  Uncle  Buht: "Let me through... Let me.. Break it down, hell with
019                 it..." Wet with icy sweat, he slintly rolled off  his  bed,  ducked  into  a
020                 secter  closet,  and  loosing  himself  he ran down the underground passage.
021                 Something sqelched under his bare feet, the startled rats dashed  away,  but
022                 he  did  not notice anything, just now, sitting next to a wall he remembered
023                 everything; the darkness, the slippery walls, and the pain from  a  blow  on
024                 the  head against the shakled door to the temple, and his own unberable high
025                 yelp.</div>
026                 <div>They shall not enter here, he thought. No one shall enter here. Only if
027                 the King  order's  so.  But  the  King  shall  not  order...  He   snickered
028                 hysterically. Oh no, the King will not order! He carefully un screwed up his
029                 eyes  and  saw  his  blue, hairless legs with scraped knees. Still alive, he
030                 thought. I will live, because they shall not enter here.</div>
031                 <div>Everything in the temple  was  blueish  from  the  cold  light  of  the
032                 lanterns -- long glowing tubes that were stretched under the ceiling. In the
033                 center,  God stood on an eminence, big, heavy, with sparkling dead eyes. The
034                 King continuously and stupidly stared, until God was suddenly screened by  a
035                 shabby  lay  brother,  still  a  greenhorn. Scraching, with an open mouth he
036                 gazed at the naked King. The King squinted once again. Scum, he  thought,  a
037                 lousy  vermine,  catch the mongrel and to the dogs, for them to ravage... He
038                 reasoned that he did not remember the lout well, but he was  long  gone.  So
039                 scrawny,   snotty...   That's  all  right,  we'll  remember.  We'll  remeber
040                 everything, Your Highness, Uncle Buht. During the father's  reighn,  I  dare
041                 say you sat quietly, drank a bit and kept silent, were afraid to be noticed,
042                 you knew that King Prostyaga did not forget you ignoble treachery...</div>
043                 <div>Great  was  the father, the King thought with an accustomed envy. You'd
044                 be great, if your advisors are God's angels in flesh.  All  know,  all  have
045                 seen  them:  their  faces  fearful, white, like milk, and their garment were
046                 such that one could not understand if they were  naked  or  not.  And  their
047                 arrows  were  fiery,  like  lightning,  they  drove  off the nomads with the
048                 arrows, and although they casted them overhead, half the horde cripled  from
049                 fear.  His  Highness,  Uncle  Buht,  wispered  once  upon  a time, drunk and
050                 burping, that those arrows can be cast by anyone, that  special  slings  are
051                 needed that the angels have and that would be nice to take from them. And he
052                 said  then -- he was drunk then, -- that if it is nice to have, why not have
053                 it, why not... Soon after that table talk one angel fell off the  wall  into
054                 the  moat,  probably  slipped.  Next  to  him they found one of uncle's body
055                 guards with a javelin between his shoulder  blades.  It  was  a  dark,  dark
056                 deed...  It  good  that  the people did not care about the angels, they were
057                 scary to look at, but it is not clear why is it scary -- angels were  happy,
058                 cordial  people.  Only  their  eyes  were scary. Small, shiny, and they keep
059                 racing around... non humanoid eyes, not peaceful. So the people hushed down,
060                 although father, King Prostyaga gave them such freedom that it  is  shameful
061                 to  remember...  although,  before  the  Coup, father, they say was a saddle
062                 maker. For saying so, with my own hands I had torn eyes out, and sewen  ears
063                 shut.  But  I remember, he used to sit in the evenings by the Crystal Tower,
064                 and he would cut out leather -- beautiful work. And I would perch myself  at
065                 his  side, it's warm and comfy... The angels were singing from the rooms, so
066                 quietly, and in harmony, and father would start  to  accompany  --  he  knew
067                 their  language  --  it  used to be spacious, nobody around... not like now,
068                 guards are stuck at every corner, but there is no sense in it...</div>
069                 <div>The King lamented. Yes, he was a good father, just that he did not  die
070                 for  a long time. You can't do that while your son is still alive... The son
071                 is also the King, the son also want's to... But Prostyaga did not  age,  I'm
072                 over  fifty,and  he  still looks younger than me... It looks like the angels
073                 had asked God for his health... They asked for his health, but  they  forgot
074                 about  me.  They  say  that  the  second one they managed to pin down in the
075                 father's room, he had a sling in each hand, but he  did  not  fight.  Before
076                 death,  they  say,  he  threw both of them out the window, they burst into a
077                 blue flame, there was no dust  left...  Too  bad  about  the  slings...  And
078                 Prostyaga, they say, cried and got drunk then, within an inch of his life --
079                 the  first  time  since  his  reign  --  looked for me, they said, loved me,
080                 believed...</div>
081                 <div>The King drew his knees to his chin, and hugged his leggs. So  what  if
082                 he  believed?  One  should  know  one's  limit,  abdicate,  like  it is done
083                 elsewhere... and I do not know anything, and do not want to. There was  only
084                 a conversation with my uncle, His Highnesss.</div>
085                 <div>"Prostyaga, -- he said, -- doesn't age". -- "Yes, -- I tell him, -- but
086                 what can  we  do,  the  angels  pleaded for his health." Uncle then sneered,
087                 scum, and wispered: "Angels, -- he said,  --  no  longer  sing  their  songs
088                 here".  And  I blurted out: "It is true, but now there is a way to deal with
089                 them, not just with humans". Uncle looked at me  soberly,  and  immediatelly
090                 left...  And I didn't really say anything... Empty words, without meaning...
091                 And in a week Prostyaga died from a heart attack. So what? It was his  time.
092                 He looked young, but in reality he was over one hundred. We'll all die...</div>
093                 <div>The King was startled, and covering himself, awkwardly sat up. Into the
094                 temple  came  the  High  Priest  Agar.  Lay brothers were leading him by the
095                 hands. He didn't look at the King, came up to God and kneeled  in  front  of
096                 the  eminence,  tall,  hunch-backed, with waist length dirty-white hair. The
097                 King gloated "It's the end of you, Your Highness, you did  manage,  I'm  not
098                 like  Prostyaga,  you'll  ravage your oun intestines, drunken swine..." Agar
099                 spoke in a rich voice:</div>
100                 <div>- God! The King wishes to speak to you! Forgive him and listen!</div>
101                 <div>The room fell silent, no-one dared to breathe. The  King  contemplated:
102                 when  the  great flood happened, and the earth burst, Prostyaga asked God to
103                 help, and God came down from the sky as a ball of flame on the same day, and
104                 that night the earth closed up, and the flood  disappeared.  It  means  that
105                 this  is  how  it will happen today. You were late uncle, Your Highness, you
106                 didn't manage. No one can help you now...</div>
107                 <div>Agar straighned up. The lay brothers that supported him,  jumped  away,
108                 turned with their backs to God, and covered their heads with their arms. The
109                 Kind  saw,  how  Agar stretced his clasped hands and put them on Gods chest.
110                 God's eyes lit up. The King snapped his jaw from fear: the eyes were big and
111                 different -- one was snakish-green, the other white, as bright as light. One
112                 could hear how  God  started  to  breathe,  heavily,  with  crackling,  like
113                 consumption. Agar backed away.</div>
114                 <div>- Speak, - he whispered. It looked like he was unsettled as well.</div>
115                 <div>The King lowered to all fours, and started to crawl to the eminence. He
116                 did not  know what to do or how. And he did not know how he should start and
117                 whether he should tell the complete truth. God  breathed  heavily,  weezing,
118                 suddenly he started to whimper, quietly and thinly - scary.</div>
119                 <div>- I'm  the son of Prostyaga -- said the King in despair, smothering his
120                 face against the cold stone. -- Prostyaga died. I ask  protection  from  the
121                 conspirators.  Prostyaga made mistakes. He did not know what he was doing. I
122                 have fixed everything: calmed the people, became great and unatainable, like
123                 you, I gathered an army... And the treacherous Buht is disrupting  my  plans
124                 to conquer the world... He wants to kill me! Help me!</div>
125                 <div>He raised his head. God, without blinking, was looking in his face with
126                 green and white. God was silent.</div>
127                 <div>- Help me... - repeated the King. -- Help! Help! - He suddenly thought,
128                 that he  is  doing something wrong, and that God is indifferent towards him,
129                 and inopportunely remembered: they said, his father, Prostyaga, did not  die
130                 from  a  heart  attack,  but was killed here, in the temple when the killers
131                 came in, with out asking permission. -- Help!.-- he  screemed  desperatelly.
132                 -- I'm afraid to die today! Help! Help!</div>
133                 <div>He  hunched  up  on the stone tiles, biting his hands from an unbarable
134                 terror. Differently-eyed God hoarsly breathed above his head.</div>
135                 <div>- Old vermine, - said Tolya. Ernst was quiet. On  the  screen,  through
136                 the  sparks  of  static an ugly black shape of a human lay splattered on the
137                 floor. -- When I think, Tolya spoke again, -- that if not for him, Alan  and
138                 Derek would be alive, I want to do something, that you never wanted to do.</div>
139                 <div>Ernst shrugged his shoulders and moved to the table.</div>
140                 <div>- And  I  always think, - Tolya continued, - why didn't Derek shoot? He
141                 could have killed all...</div>
142                 <div>- He couldn't , - said Ernst.</div>
143                 <div>- Why couldn't he?</div>
144                 <div>- Have you ever tried shooting at a human being?</div>
145                 <div>Tolya made a wry face, but didn't say anything.</div>
146                 <div>- Well that's what it was, - said Ernst. -- Try to imagine  it.  It  is
147                 almost as disgusting.</div>
148                 <div>A  sorowful howl was heard from the loudspeaker. "HELP HELP I AM AFRAID
149                 HELP..," the auto-translater was writing.</div>
150                 <div>- Poor cruel folk... - said Tolya.</div>
151             </div>
152         </div>
153     </div>
154 </body>
155 </html>

This is sample of content (from one book) – it have pretty much text, right? Soon (at third step) we will apply pagination to our ‘main_content’.

Step 2. CSS

Here are used CSS file with styles of our demo:

css/main.css

01 body {
02 background:#eee;
03 margin:0;
04 padding:0;
05 }
06 .example {
07 -moz-border-radius:3px;
08 -webkit-border-radius:3px;
09 background:#FFF;
10 border:1px #000 solid;
11 height:600px;
12 margin:20px auto;
13 padding:15px;
14 position:relative;
15 width:800px;
16 }
17 #main_content {
18 height:50%;
19 left:5%;
20 overflow:auto;
21 position:absolute;
22 top:5%;
23 width:90%;
24 }
25 .ssb_down {
26 background:transparent url(../images/icon-arrow-down.png);
27 bottom:0;
28 cursor:pointer;
29 position:absolute;
30 right:0;
31 }
32 .ssb_sb {
33 background:transparent url(../images/middle.png);
34 cursor:pointer;
35 position:absolute;
36 right:0;
37 }
38 .ssb_sb_down {
39 background:transparent url(../images/middrag.png);
40 }
41 .ssb_sb_over {
42 background:transparent url(../images/midhover.png);
43 }
44 .ssb_st {
45 background:transparent url(../images/back.png);
46 cursor:pointer;
47 height:100%;
48 position:absolute;
49 right:0;
50 top:0;
51 }
52 .ssb_up {
53 background:transparent url(../images/icon-arrow-up.png);
54 cursor:pointer;
55 position:absolute;
56 right:0;
57 top:0;
58 }
59 .parent {
60 font-family:verdana;
61 height:100%;
62 padding:10px;
63 position:relative;
64 }

Step 3. JS

Here are all JS files:

js/main.js

001 var ssb = {
002     aConts  : [],
003     mouseY : 0,
004     N  : 0,
005     asd : 0, /*active scrollbar element*/
006     sc : 0,
007     sp : 0,
008     to : 0,
009     // constructor
010     scrollbar : function (cont_id) {
011         var cont = document.getElementById(cont_id);
012         // perform initialization
013         if (! ssb.init()) return false;
014         var cont_clone = cont.cloneNode(false);
015         cont_clone.style.overflow = "hidden";
016         cont.parentNode.appendChild(cont_clone);
017         cont_clone.appendChild(cont);
018         cont.style.position = 'absolute';
019         cont.style.left = cont.style.top = '0px';
020         cont.style.width = cont.style.height = '100%';
021         // adding new container into array
022         ssb.aConts[ssb.N++] = cont;
023         cont.sg = false;
024         //creating scrollbar child elements
025         cont.st = this.create_div('ssb_st', cont, cont_clone);
026         cont.sb = this.create_div('ssb_sb', cont, cont_clone);
027         cont.su = this.create_div('ssb_up', cont, cont_clone);
028         cont.sd = this.create_div('ssb_down', cont, cont_clone);
029         // on mouse down processing
030         cont.sb.onmousedown = function (e) {
031             if (! this.cont.sg) {
032                 if (! e) e = window.event;
033                 ssb.asd = this.cont;
034                 this.cont.yZ = e.screenY;
035                 this.cont.sZ = cont.scrollTop;
036                 this.cont.sg = true;
037                 // new class name
038                 this.className = 'ssb_sb ssb_sb_down';
039             }
040             return false;
041         }
042         // on mouse down on free track area - move our scroll element too
043         cont.st.onmousedown = function (e) {
044             if (! e) e = window.event;
045             ssb.asd = this.cont;
046             ssb.mouseY = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
047             for (var o = this.cont, y = 0; o != null; o = o.offsetParent) y += o.offsetTop;
048             this.cont.scrollTop = (ssb.mouseY - y - (this.cont.ratio * this.cont.offsetHeight / 2) - this.cont.sw) / this.cont.ratio;
049             this.cont.sb.onmousedown(e);
050         }
051         // onmousedown events
052         cont.su.onmousedown = cont.su.ondblclick = function (e) { ssb.mousedown(this, -1); return false; }
053         cont.sd.onmousedown = cont.sd.ondblclick = function (e) { ssb.mousedown(this,  1); return false; }
054         //onmouseout events
055         cont.su.onmouseout = cont.su.onmouseup = ssb.clear;
056         cont.sd.onmouseout = cont.sd.onmouseup = ssb.clear;
057         // on mouse over - apply custom class name: ssb_sb_over
058         cont.sb.onmouseover = function (e) {
059             if (! this.cont.sg) this.className = 'ssb_sb ssb_sb_over';
060             return false;
061         }
062         // on mouse out - revert back our usual class name 'ssb_sb'
063         cont.sb.onmouseout  = function (e) {
064             if (! this.cont.sg) this.className = 'ssb_sb';
065             return false;
066         }
067         // onscroll - change positions of scroll element
068         cont.ssb_onscroll = function () {
069             this.ratio = (this.offsetHeight - 2 * this.sw) / this.scrollHeight;
070             this.sb.style.top = Math.floor(this.sw + this.scrollTop * this.ratio) + 'px';
071         }
072         // scrollbar width
073         cont.sw = 20;
074         // start scrolling
075         cont.ssb_onscroll();
076         ssb.refresh();
077         // binding own onscroll event
078         cont.onscroll = cont.ssb_onscroll;
079         return cont;
080     },
081     // initialization
082     init : function () {
083         if (window.oper || (! window.addEventListener && ! window.attachEvent)) { return false; }
084         // temp inner function for event registration
085         function addEvent (o, e, f) {
086             if (window.addEventListener) { o.addEventListener(e, f, false); ssb.w3c = truereturn true; }
087             if (window.attachEvent) return o.attachEvent('on' + e, f);
088             return false;
089         }
090         // binding events
091         addEvent(window.document, 'mousemove', ssb.onmousemove);
092         addEvent(window.document, 'mouseup', ssb.onmouseup);
093         addEvent(window, 'resize', ssb.refresh);
094         return true;
095     },
096     // create and append div finc
097     create_div : function(c, cont, cont_clone) {
098         var o = document.createElement('div');
099         o.cont = cont;
100         o.className = c;
101         cont_clone.appendChild(o);
102         return o;
103     },
104     // do clear of controls
105     clear : function () {
106         clearTimeout(ssb.to);
107         ssb.sc = 0;
108         return false;
109     },
110     // refresh scrollbar
111     refresh : function () {
112         for (var i = 0, N = ssb.N; i < N; i++) {
113             var o = ssb.aConts[i];
114             o.ssb_onscroll();
115             o.sb.style.width = o.st.style.width = o.su.style.width = o.su.style.height = o.sd.style.width = o.sd.style.height = o.sw + 'px';
116             o.sb.style.height = Math.ceil(Math.max(o.sw * .5, o.ratio * o.offsetHeight) + 1) + 'px';
117         }
118     },
119     // arrow scrolling
120     arrow_scroll : function () {
121         if (ssb.sc != 0) {
122             ssb.asd.scrollTop += 6 * ssb.sc / ssb.asd.ratio;
123             ssb.to = setTimeout(ssb.arrow_scroll, ssb.sp);
124             ssb.sp = 32;
125         }
126     },
127     /* event binded functions : */
128     // scroll on mouse down
129     mousedown : function (o, s) {
130         if (ssb.sc == 0) {
131             // new class name
132             o.cont.sb.className = 'ssb_sb ssb_sb_down';
133             ssb.asd = o.cont;
134             ssb.sc = s;
135             ssb.sp = 400;
136             ssb.arrow_scroll();
137         }
138     },
139     // on mouseMove binded event
140     onmousemove : function(e) {
141         if (! e) e = window.event;
142         // get vertical mouse position
143         ssb.mouseY = e.screenY;
144         if (ssb.asd.sg) ssb.asd.scrollTop = ssb.asd.sZ + (ssb.mouseY - ssb.asd.yZ) / ssb.asd.ratio;
145     },
146     // on mouseUp binded event
147     onmouseup : function (e) {
148         if (! e) e = window.event;
149         var tg = (e.target) ? e.target : e.srcElement;
150         if (ssb.asd && document.releaseCapture) ssb.asd.releaseCapture();
151         // new class name
152         if (ssb.asd) ssb.asd.sb.className = (tg.className.indexOf('scrollbar') > 0) ? 'ssb_sb ssb_sb_over' 'ssb_sb';
153         document.onselectstart = '';
154         ssb.clear();
155         ssb.asd.sg = false;
156     }
157 }
158 window.onload = function() {
159     ssb.scrollbar('main_content'); // scrollbar initialization
160 }

Binded events, other scrolling functionality – all here. I tried to make comments in many important places.


Live Demo

Conclusion

Today`s article told you about creating nice customized scrollbar for content. Sure that this was useful for you. Your comments are welcome. Good luck!

Rate article