├── .gitignore ├── js ├── demo.js ├── rocketHelpers.js ├── rocketScroll.min.js └── rocketScroll.js ├── sass ├── demo.scss ├── reset.scss └── rocketScroll.scss ├── css ├── rocketScroll.css └── demo.css ├── README.md └── index.html /.gitignore: -------------------------------------------------------------------------------- 1 | */.DS_STORE 2 | .DS_STORE -------------------------------------------------------------------------------- /js/demo.js: -------------------------------------------------------------------------------- 1 | var rsSingle, rsMultiple; 2 | 3 | rsSingle = new RS.RocketScroll('#scroll'); 4 | 5 | rsMultiple = new RS.RocketScroll('.multiple'); -------------------------------------------------------------------------------- /sass/demo.scss: -------------------------------------------------------------------------------- 1 | @import 'reset'; 2 | 3 | *{ 4 | -webkit-box-sizing: border-box; 5 | -moz-box-sizing: border-box; 6 | box-sizing: border-box; 7 | } 8 | body{ 9 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 10 | font-size: 16px; 11 | font-weight: 200; 12 | color: #333; 13 | background: #f3f6f9; 14 | margin: 40px; 15 | } 16 | h1, h2, h3 { 17 | font-size: 32px; 18 | font-weight: 200; 19 | margin-bottom: 10px; 20 | } 21 | h2{ font-size: 24px; } 22 | h3{ font-size: 20px; } 23 | p{ 24 | margin-bottom: 15px; 25 | line-height: 1.4em; 26 | } 27 | .big{ 28 | font-size: 18px; 29 | } 30 | 31 | .scroll{ 32 | float: left; 33 | width: 300px; 34 | height: 400px; 35 | 36 | position: relative; 37 | margin: 20px 40px 40px 0; 38 | border: 1px solid #666; 39 | background: #f9f9f9; 40 | border-radius: 2px; 41 | box-shadow: 2px 2px 2px rgba(0,0,0,0.2); 42 | overflow-y: scroll; 43 | } 44 | hr{ 45 | border: none; 46 | border-top: 1px solid #666; 47 | margin: 15px 0 14px; 48 | } -------------------------------------------------------------------------------- /sass/reset.scss: -------------------------------------------------------------------------------- 1 | /* http://meyerweb.com/eric/tools/css/reset/ 2 | v2.0 | 20110126 3 | License: none (public domain) 4 | */ 5 | 6 | html, body, div, span, applet, object, iframe, 7 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 8 | a, abbr, acronym, address, big, cite, code, 9 | del, dfn, em, img, ins, kbd, q, s, samp, 10 | small, strike, strong, sub, sup, tt, var, 11 | b, u, i, center, 12 | dl, dt, dd, ol, ul, li, 13 | fieldset, form, label, legend, 14 | table, caption, tbody, tfoot, thead, tr, th, td, 15 | article, aside, canvas, details, embed, 16 | figure, figcaption, footer, header, hgroup, 17 | menu, nav, output, ruby, section, summary, 18 | time, mark, audio, video { 19 | margin: 0; 20 | padding: 0; 21 | border: 0; 22 | font-size: 100%; 23 | font: inherit; 24 | vertical-align: baseline; 25 | } 26 | /* HTML5 display-role reset for older browsers */ 27 | article, aside, details, figcaption, figure, 28 | footer, header, hgroup, menu, nav, section { 29 | display: block; 30 | } 31 | body { 32 | line-height: 1; 33 | } 34 | ol, ul { 35 | list-style: none; 36 | } 37 | blockquote, q { 38 | quotes: none; 39 | } 40 | blockquote:before, blockquote:after, 41 | q:before, q:after { 42 | content: ''; 43 | content: none; 44 | } 45 | table { 46 | border-collapse: collapse; 47 | border-spacing: 0; 48 | } -------------------------------------------------------------------------------- /sass/rocketScroll.scss: -------------------------------------------------------------------------------- 1 | @mixin border-box(){ 2 | -webkit-box-sizing: border-box; 3 | -moz-box-sizing: border-box; 4 | box-sizing: border-box; 5 | } 6 | 7 | @mixin unselectable(){ 8 | -moz-user-select: none; 9 | -webkit-user-select: none; 10 | -ms-user-select: none; 11 | user-select: none; 12 | } 13 | 14 | .rocketScroll{ 15 | overflow: hidden !important; 16 | position: relative; 17 | 18 | .scrollDiv{ 19 | @include border-box; 20 | overflow-y: scroll; 21 | height: 100%; 22 | } 23 | .scrollContent{ 24 | @include border-box; 25 | padding: 20px; 26 | } 27 | 28 | .scrollbar { 29 | position: absolute; 30 | right: 6px; 31 | top: 6px; 32 | bottom: 6px; 33 | background: transparent; 34 | width: 6px; 35 | border-radius: 3px; 36 | transition: background-color 0.5s; 37 | &:hover{ 38 | cursor: pointer; 39 | div:hover{ 40 | background: #777; 41 | background: rgba(0,0,0,0.55); 42 | } 43 | } 44 | &, & div{ 45 | @include unselectable; 46 | } 47 | } 48 | 49 | .scrollbar div{ 50 | height: 100px; 51 | width: 6px; 52 | border-radius: 3px; 53 | background: transparent; 54 | transition: background-color 0.5s; 55 | } 56 | 57 | &:hover{ 58 | .scrollbar{ 59 | background: #ddd; 60 | background: rgba(0,0,0,0.15); 61 | } 62 | .scrollbar div{ 63 | background: #aaa; 64 | background: rgba(0,0,0,0.35); 65 | } 66 | } 67 | 68 | .unselectable { 69 | @include unselectable; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /css/rocketScroll.css: -------------------------------------------------------------------------------- 1 | .rocketScroll { 2 | overflow: hidden !important; 3 | position: relative; } 4 | .rocketScroll .scrollDiv { 5 | -webkit-box-sizing: border-box; 6 | -moz-box-sizing: border-box; 7 | box-sizing: border-box; 8 | overflow-y: scroll; 9 | height: 100%; } 10 | .rocketScroll .scrollContent { 11 | -webkit-box-sizing: border-box; 12 | -moz-box-sizing: border-box; 13 | box-sizing: border-box; 14 | padding: 20px; } 15 | .rocketScroll .scrollbar { 16 | position: absolute; 17 | right: 6px; 18 | top: 6px; 19 | bottom: 6px; 20 | background: transparent; 21 | width: 6px; 22 | border-radius: 3px; 23 | transition: background-color 0.5s; } 24 | .rocketScroll .scrollbar:hover { 25 | cursor: pointer; } 26 | .rocketScroll .scrollbar:hover div:hover { 27 | background: #777; 28 | background: rgba(0, 0, 0, 0.55); } 29 | .rocketScroll .scrollbar, .rocketScroll .scrollbar div { 30 | -moz-user-select: none; 31 | -webkit-user-select: none; 32 | -ms-user-select: none; 33 | user-select: none; } 34 | .rocketScroll .scrollbar div { 35 | height: 100px; 36 | width: 6px; 37 | border-radius: 3px; 38 | background: transparent; 39 | transition: background-color 0.5s; } 40 | .rocketScroll:hover .scrollbar { 41 | background: #ddd; 42 | background: rgba(0, 0, 0, 0.15); } 43 | .rocketScroll:hover .scrollbar div { 44 | background: #aaa; 45 | background: rgba(0, 0, 0, 0.35); } 46 | .rocketScroll .unselectable { 47 | -moz-user-select: none; 48 | -webkit-user-select: none; 49 | -ms-user-select: none; 50 | user-select: none; } 51 | -------------------------------------------------------------------------------- /css/demo.css: -------------------------------------------------------------------------------- 1 | /* http://meyerweb.com/eric/tools/css/reset/ 2 | v2.0 | 20110126 3 | License: none (public domain) 4 | */ 5 | html, body, div, span, applet, object, iframe, 6 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 7 | a, abbr, acronym, address, big, cite, code, 8 | del, dfn, em, img, ins, kbd, q, s, samp, 9 | small, strike, strong, sub, sup, tt, var, 10 | b, u, i, center, 11 | dl, dt, dd, ol, ul, li, 12 | fieldset, form, label, legend, 13 | table, caption, tbody, tfoot, thead, tr, th, td, 14 | article, aside, canvas, details, embed, 15 | figure, figcaption, footer, header, hgroup, 16 | menu, nav, output, ruby, section, summary, 17 | time, mark, audio, video { 18 | margin: 0; 19 | padding: 0; 20 | border: 0; 21 | font-size: 100%; 22 | font: inherit; 23 | vertical-align: baseline; } 24 | 25 | /* HTML5 display-role reset for older browsers */ 26 | article, aside, details, figcaption, figure, 27 | footer, header, hgroup, menu, nav, section { 28 | display: block; } 29 | 30 | body { 31 | line-height: 1; } 32 | 33 | ol, ul { 34 | list-style: none; } 35 | 36 | blockquote, q { 37 | quotes: none; } 38 | 39 | blockquote:before, blockquote:after, 40 | q:before, q:after { 41 | content: ''; 42 | content: none; } 43 | 44 | table { 45 | border-collapse: collapse; 46 | border-spacing: 0; } 47 | 48 | * { 49 | -webkit-box-sizing: border-box; 50 | -moz-box-sizing: border-box; 51 | box-sizing: border-box; } 52 | 53 | body { 54 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 55 | font-size: 16px; 56 | font-weight: 200; 57 | color: #333; 58 | background: #f3f6f9; 59 | margin: 40px; } 60 | 61 | h1, h2, h3 { 62 | font-size: 32px; 63 | font-weight: 200; 64 | margin-bottom: 10px; } 65 | 66 | h2 { 67 | font-size: 24px; } 68 | 69 | h3 { 70 | font-size: 20px; } 71 | 72 | p { 73 | margin-bottom: 15px; 74 | line-height: 1.4em; } 75 | 76 | .big { 77 | font-size: 18px; } 78 | 79 | .scroll { 80 | float: left; 81 | width: 300px; 82 | height: 400px; 83 | position: relative; 84 | margin: 20px 40px 40px 0; 85 | border: 1px solid #666; 86 | background: #f9f9f9; 87 | border-radius: 2px; 88 | box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.2); 89 | overflow-y: scroll; } 90 | 91 | hr { 92 | border: none; 93 | border-top: 1px solid #666; 94 | margin: 15px 0 14px; } 95 | -------------------------------------------------------------------------------- /js/rocketHelpers.js: -------------------------------------------------------------------------------- 1 | /* 2 | Written by Stanko 3 | RocketHelpers - it will become micro library at some point 4 | http://www.rocketlaunch.me 5 | */ 6 | 7 | if (!window.getComputedStyle) { 8 | window.getComputedStyle = function(el, pseudo) { 9 | this.el = el; 10 | this.getPropertyValue = function(prop) { 11 | var re = /(\-([a-z]){1})/g; 12 | if (prop === 'float'){ 13 | prop = 'styleFloat'; 14 | } 15 | if (re.test(prop)) { 16 | prop = prop.replace(re, function () { 17 | return arguments[2].toUpperCase(); 18 | }); 19 | } 20 | return el.currentStyle[prop] ? el.currentStyle[prop] : null; 21 | }; 22 | return this; 23 | }; 24 | } 25 | 26 | var RS = RS || {}; 27 | 28 | RS.getScrollTop = function(){ 29 | if(typeof pageYOffset !== 'undefined'){ 30 | // Most browsers 31 | return pageYOffset; 32 | } 33 | else{ 34 | var b = document.body, //IE 'quirks' 35 | d = document.documentElement; //IE with doctype 36 | d = (d.clientHeight) ? d : b; 37 | return d.scrollTop; 38 | } 39 | }; 40 | 41 | // Gets Y offset of event, relative to source element 42 | // Calculating X is commented, as this plugin is not using it 43 | RS.getOffset = function(e) { 44 | var el = e.target ? e.target : e.srcElement, // IE Check 45 | //x = 0, 46 | y = 0; 47 | 48 | while (el && !isNaN(el.offsetLeft) && !isNaN(el.offsetTop)) { 49 | //x += el.offsetLeft - el.scrollLeft; 50 | y += el.offsetTop - el.scrollTop; 51 | el = el.offsetParent; 52 | } 53 | 54 | //x = e.clientX + RS.getScrollLeft() - x; 55 | y = e.clientY + RS.getScrollTop() - y; 56 | 57 | //return { x: x, y: y }; 58 | return y; 59 | }; 60 | 61 | RS.stopPropagation = function(e){ 62 | e = e || window.event; // IE Fix 63 | 64 | if(e.stopPropagation){ 65 | e.stopPropagation(); 66 | } 67 | else{ 68 | // IE8 and lower stop propagation 69 | window.event.cancelBubble = true; 70 | window.event.returnValue = false; 71 | } 72 | }; 73 | 74 | 75 | RS.originalOnselectstart = false; 76 | 77 | RS.enableSelection = function(enable) { 78 | if(enable) { 79 | window.document.onselectstart = RS.originalOnselectstart; 80 | } 81 | else { 82 | RS.originalOnselectstart = window.document.onselectstart; 83 | window.document.onselectstart = function() { 84 | return false; 85 | }; 86 | } 87 | }; 88 | 89 | RS.$ = function (s) { 90 | var r = document.querySelectorAll(s); 91 | return r.length === 1 ? r[0] : r; 92 | }; 93 | 94 | RS.detectTouchScreen = function(){ 95 | return ('ontouchstart' in document.documentElement); 96 | }; 97 | 98 | RS.detectIE = function(){ 99 | return document.all ? true : false; 100 | }; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | rocketScroll 2 | ============ 3 | 4 | Pure JavaScript scroll bar script. Support native mouse wheel scroll. Easy customizable css. Works even in IE8+. 5 | 6 | Made with love <3 7 | 8 | I decided to biuld this, as didn't find single plain JavaScript script that actually works. Either that, or those would need whole jQuery with plugins for mouse scroll and stuff... This script is really small, and uses simple trick to preserve native mouse wheel / arrows scroll. It is done by css, and element that is actually scrolling is 50px wider than the parent. So native scroll bar is still there and works, but hidden from the eye of the user. 9 | 10 | ## DEMO 11 | 12 | [Click here for demo](http://stanko.github.io/rocketScroll/). 13 | 14 | ## Why you should use it 15 | 16 | * Plain JavaScript, very small (2kb minifed/gzipped, 1kb of CSS) no jQuery or external libs 17 | * Works in all modern browsers and even IE. Tested in FF 21, Chrome 27, IE 8, IE 9, Safari 6 18 | * Easy customizable via CSS 19 | * Native arrows / mouse wheel support 20 | 21 | 22 | ## Usage 23 | 24 | HTML, why three divs? We need three divs to preserve native scroll. I used to create other two 25 | in JavaScript, but that makes updating content and woking with events a lot harder. 26 | I switched back to manual HTML coding, but still I think it is pretty simple. 27 | 28 |
29 |
30 |
31 | YOUR CONTENT HERE 32 |
33 |
34 |
35 | 36 | Then just pass CSS selector, (in IE8 only CSS 2.1 selectors). 37 | 38 | ``var rsSingle = new RS.RocketScroll('#scrollDiv');`` 39 | 40 | ``var rsMultiple = new RS.RocketScroll('.scrollDiv');`` 41 | 42 | 43 | ### .refresh(updateImagesOnload) 44 | 45 | NOTICE!!! After manual updating the content, you need to call `.refresh()` method. It works for both single and multiple scrolls. 46 | 47 | 48 | (Optional) If you send `updateImagesOnload = true`, method will call `.refreshImages()`. Default is `false`; 49 | 50 | 51 | ### .refreshImages() 52 | 53 | On init and content updating, script calls this method, to update itself on every image load. 54 | 55 | 56 | ## Known issues 57 | 58 | Looks like there is crapload of issues - but don't worry! Most of them are minor, and will be solved in reasonable time. 59 | 60 | * Doesn't work properly when used on the body tag. Not sure if I'm going to fix this - just use one wrapper div :) 61 | * ~~In webkit browsers (Chrome, Safari) you can scroll right by selecting text. I have a dirty fix, which just resets the scroll. Looking for more elegant solution. FIXED~~ 62 | * ~~Need to replace event.layerY property with something else as it is deprecated in new broswers, and it doesn't work in IE8. FIXED~~ 63 | * ~~Clicking on the scrollbar doesn't scroll in IE8 for that reason FIXED~~ 64 | * When scrolling by pulling handle, if mouse leaves the element, scroll is stopped. This is due the glitch in IE/webkit (It made element "locked" in scroll mode on the next mouse enter, untill you click somewhere.) 65 | * Using nested scrolls make inner scrollbars show when hovering parent scroll element. This is handled by CSS, maybe switch to JS. 66 | 67 | Please give suggestions, fork, upgrade, share, use and abuse it! Pull request are more than welcome :) 68 | 69 | Hope you like it :) 70 | Cheers! 71 | -------------------------------------------------------------------------------- /js/rocketScroll.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | Written by Stanko 3 | RocketHelpers - it will become micro library at some point 4 | http://www.rocketlaunch.me 5 | */window.getComputedStyle||(window.getComputedStyle=function(e,t){this.el=e;this.getPropertyValue=function(t){var n=/(\-([a-z]){1})/g;t==="float"&&(t="styleFloat");n.test(t)&&(t=t.replace(n,function(){return arguments[2].toUpperCase()}));return e.currentStyle[t]?e.currentStyle[t]:null};return this});var RS=RS||{};RS.getScrollTop=function(){if(typeof pageYOffset!="undefined")return pageYOffset;var e=document.body,t=document.documentElement;t=t.clientHeight?t:e;return t.scrollTop};RS.getOffset=function(e){var t=e.target?e.target:e.srcElement,n=0;while(t&&!isNaN(t.offsetLeft)&&!isNaN(t.offsetTop)){n+=t.offsetTop-t.scrollTop;t=t.offsetParent}n=e.clientY+RS.getScrollTop()-n;return n};RS.stopPropagation=function(e){e=e||window.event;if(e.stopPropagation)e.stopPropagation();else{window.event.cancelBubble=!0;window.event.returnValue=!1}};RS.originalOnselectstart=!1;RS.enableSelection=function(e){if(e)window.document.onselectstart=RS.originalOnselectstart;else{RS.originalOnselectstart=window.document.onselectstart;window.document.onselectstart=function(){return!1}}};RS.$=function(e){var t=document.querySelectorAll(e);return t.length===1?t[0]:t};RS.detectTouchScreen=function(){return"ontouchstart"in document.documentElement};RS.detectIE=function(){return document.all?!0:!1};var RS=RS||{};RS.__id=0;RS.RocketScroll=function(e,t){if(RS.detectTouchScreen())return;t=t||!1;t?this.el=e:this.el=RS.$(e);if(typeof this.el.length!="undefined"&&this.el.length>1){this.elements=[];for(var n=0;nthis.contentDiv.clientHeight?this.scrollbar.style.display="none":this.scrollbar.style.display="block";this.handle.style.height=this.scrollDiv.clientHeight*(this.scrollDiv.clientHeight/this.contentDiv.clientHeight)+"px";this.totalScrollable=this.contentDiv.clientHeight-this.scrollDiv.clientHeight;this.totalHandle=this.scrollbar.clientHeight-this.handle.clientHeight;this.ratio=this.totalHandle/this.totalScrollable;this.handle.style.marginTop=this.ratio*this.scrollDiv.scrollTop+"px";this.refreshImages()};RS.RocketScroll.prototype.refreshImages=function(){var e,t,n;e=RS.$("#"+this.el.id+" .scrollContent img");if(e.length>0){t=this;for(n=0;n 1){ 30 | this.elements = []; 31 | for(var i = 0; i < this.el.length; i++){ 32 | this.elements.push( new RS.RocketScroll(this.el.item(i) , true) ); 33 | } 34 | this.multiple = true; 35 | return; 36 | } 37 | else{ 38 | this.multiple = false; 39 | } 40 | 41 | // Adds ID to the element if there is none 42 | if(!this.el.id){ 43 | this.el.id = 'rocketScroll' + (RS.__id++); 44 | } 45 | 46 | this.el.className += ' rocketScroll'; 47 | 48 | this.mouseDown = false; 49 | 50 | this.UNSELECTABLE_CLASS = ' unselectable'; 51 | 52 | this.buildHTML(); 53 | this.addScrollbar(); 54 | this.refresh(); 55 | this.bindEvents(); 56 | 57 | this.SELECTION_TIMEOUT = false; 58 | }; 59 | 60 | 61 | RS.RocketScroll.prototype.buildHTML = function() { 62 | // Div which is scrolled, 50px wider to hide scrollbar 63 | this.scrollDiv = RS.$('#' + this.el.id + ' .scrollDiv'); 64 | this.scrollDiv.style.width = this.el.clientWidth + 50 + 'px'; 65 | 66 | // Content div 67 | // Copies original html of the element and it's padding 68 | this.contentDiv = RS.$('#' + this.el.id + ' .scrollContent'); 69 | this.contentDiv.style.width = this.el.clientWidth + 'px'; 70 | 71 | this.refreshImages(); 72 | }; 73 | 74 | RS.RocketScroll.prototype.addScrollbar = function() { 75 | // Adds scrollbar and handle HTML 76 | 77 | this.handle = document.createElement('div'); 78 | 79 | this.scrollbar = document.createElement('div'); 80 | this.scrollbar.className += ' scrollbar'; 81 | this.scrollbar.appendChild(this.handle); 82 | 83 | this.el.appendChild(this.scrollbar); 84 | }; 85 | 86 | RS.RocketScroll.prototype.bindEvents = function(){ 87 | var self = this; 88 | 89 | // Move handle on mouse scroll 90 | this.scrollDiv.onscroll = function(){ 91 | self.handle.style.marginTop = self.ratio * this.scrollTop + 'px'; 92 | }; 93 | 94 | 95 | // Just stop propagating click to scrollbar 96 | this.handle.onclick = function(e){ 97 | RS.stopPropagation(e); 98 | }; 99 | 100 | // Detect when mouse is pressed 101 | this.handle.onmousedown = function(e){ 102 | e = e || window.event; // IE Fix 103 | 104 | RS.stopPropagation(e); 105 | 106 | self.contentDiv.className += self.UNSELECTABLE_CLASS; 107 | RS.enableSelection(false); 108 | 109 | self.clientY = e.clientY; 110 | self.scrollTop = self.scrollDiv.scrollTop; 111 | self.mouseDown = true; 112 | 113 | }; 114 | this.el.onmouseup = function(){ 115 | self.setMouseUpAndEnableSelection(self); 116 | }; 117 | 118 | // IE supports onmouseleave evenet 119 | if(RS.detectIE()){ 120 | this.el.onmouseleave = function(){ 121 | self.setMouseUpAndEnableSelection(self); 122 | }; 123 | } 124 | // Emulation for the other browsers, because they trigger mouseout on child nodes 125 | else{ 126 | this.el.onmouseout = function(e){ 127 | // Check if relatedTarget (element mouse moved on to) is child of the our element 128 | var current = e.relatedTarget; 129 | while(current){ 130 | if(current === this){ 131 | // If it is then mouse didn't left the element 132 | return; 133 | } 134 | current = current.parentNode; 135 | } 136 | self.setMouseUpAndEnableSelection(self); 137 | }; 138 | } 139 | 140 | 141 | // Handles mouse move, only when mouse is pressed 142 | this.el.onmousemove = function(e){ 143 | // User is not holding mouse button 144 | if(!self.mouseDown){ 145 | return; 146 | } 147 | 148 | e = e || window.event; // IE Fix 149 | self.scrollDiv.scrollTop = ((e.clientY - self.clientY) / self.ratio) + self.scrollTop; 150 | }; 151 | 152 | // Handles click on the scrollbar 153 | this.scrollbar.onclick = function(e){ 154 | e = e || window.event; // IE Fix 155 | 156 | RS.stopPropagation(e); 157 | 158 | // Moves center of the handle to the cursor 159 | var layerY = RS.getOffset(e) - self.handle.clientHeight / 2; 160 | 161 | self.scrollDiv.scrollTop = layerY / self.totalHandle * self.totalScrollable; 162 | }; 163 | 164 | // Dirty fix for chrome/webkit browsers where you can scroll left by selecting text 165 | this.el.onscroll = function(e){ 166 | e.preventDefault(); 167 | self.el.scrollLeft = 0; 168 | }; 169 | }; 170 | 171 | RS.RocketScroll.prototype.setMouseUpAndEnableSelection = function(instance){ 172 | instance.contentDiv.className = instance.contentDiv.className.replace(instance.UNSELECTABLE_CLASS, ''); 173 | instance.mouseDown = false; 174 | 175 | // Small delay on enabling text selecting again 176 | clearTimeout(instance.SELECTION_TIMEOUT); 177 | instance.SELECTION_TIMEOUT = setTimeout(function(){ 178 | RS.enableSelection(true); 179 | }, 500); 180 | }; 181 | 182 | RS.RocketScroll.prototype.refresh = function(updateImagesOnload){ 183 | var i; 184 | 185 | updateImagesOnload = updateImagesOnload || false; 186 | 187 | // Refresh multiple elements 188 | if(this.multiple){ 189 | for(i in this.elements){ 190 | this.elements[i].refresh(); 191 | } 192 | return; 193 | } 194 | 195 | 196 | // If content is smaller than the container 197 | if(this.scrollDiv.clientHeight > this.contentDiv.clientHeight){ 198 | this.scrollbar.style.display = 'none'; 199 | } 200 | else{ 201 | this.scrollbar.style.display = 'block'; 202 | } 203 | 204 | // Dynamic scroll handle height, as the content is smaller 205 | // handle gets bigger, as there is less to scroll 206 | this.handle.style.height = this.scrollDiv.clientHeight * (this.scrollDiv.clientHeight / this.contentDiv.clientHeight) + 'px'; 207 | 208 | // Refreshing scroll bar position and ratio 209 | // Should be called on content change 210 | this.totalScrollable = this.contentDiv.clientHeight - this.scrollDiv.clientHeight; 211 | this.totalHandle = this.scrollbar.clientHeight - this.handle.clientHeight; 212 | 213 | this.ratio = this.totalHandle / this.totalScrollable; 214 | 215 | this.handle.style.marginTop = this.ratio * this.scrollDiv.scrollTop + 'px'; 216 | 217 | this.refreshImages(); 218 | }; 219 | 220 | RS.RocketScroll.prototype.refreshImages = function() { 221 | var images, self, i; 222 | 223 | // Refresh after every image load 224 | images = RS.$('#' + this.el.id + ' .scrollContent img'); 225 | 226 | if(images.length > 0){ 227 | self = this; 228 | 229 | for(i = 0; i < images.length; i++){ 230 | images.item(i).onload = function(){ 231 | self.refresh(); 232 | // removing onload event 233 | this.onload = null; 234 | }; 235 | } 236 | } 237 | }; 238 | 239 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | RocketScroll • JavaScript that actually works (and rocks!) 5 | 6 | 7 | 8 | 9 | 10 |
11 |
12 | 13 |

RocketScroll

14 |

Pure JavaScript scroll bar, works in modern browsers and IE8+

15 |

This is just a demo, pls visit GitHUB page for readme :)

16 | 17 |
18 |
19 |
20 |

Try to scroll this div using mouse wheel

21 |

This div is activated by element id - #scroll

22 |
23 |

24 | Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. 25 |

26 |

27 | Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed posuere consectetur est at lobortis. Donec id elit non mi porta gravida at eget metus. Aenean lacinia bibendum nulla sed consectetur. 28 |

29 |

30 | Sed posuere consectetur est at lobortis. Cras mattis consectetur purus sit amet fermentum. Etiam porta sem malesuada magna mollis euismod. Donec id elit non mi porta gravida at eget metus. Etiam porta sem malesuada magna mollis euismod. 31 | 32 |

33 |

One more header

34 |

35 | Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Nulla vitae elit libero, a pharetra augue. Vestibulum id ligula porta felis euismod semper. Cras justo odio, dapibus ac facilisis in, egestas eget quam. 36 | 37 |

38 |

39 | Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed posuere consectetur est at lobortis. Donec id elit non mi porta gravida at eget metus. Aenean lacinia bibendum nulla sed consectetur. 40 | 41 |

42 |

43 | Sed posuere consectetur est at lobortis. Cras mattis consectetur purus sit amet fermentum. Etiam porta sem malesuada magna mollis euismod. Donec id elit non mi porta gravida at eget metus. Etiam porta sem malesuada magna mollis euismod. 44 |

45 |

46 | Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Nulla vitae elit libero, a pharetra augue. Vestibulum id ligula porta felis euismod semper. Cras justo odio, dapibus ac facilisis in, egestas eget quam. 47 |

48 |
49 |
50 |
51 | 52 | 53 |
54 |
55 |
56 |

Scroll me too!

57 |

This div is activated by element class - .multiple

58 |
59 |

60 | Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. 61 |

62 |

63 | Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed posuere consectetur est at lobortis. Donec id elit non mi porta gravida at eget metus. Aenean lacinia bibendum nulla sed consectetur. 64 |

65 |

66 | Sed posuere consectetur est at lobortis. Cras mattis consectetur purus sit amet fermentum. Etiam porta sem malesuada magna mollis euismod. Donec id elit non mi porta gravida at eget metus. Etiam porta sem malesuada magna mollis euismod. 67 | 68 |

69 |

One more header

70 |

71 | Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Nulla vitae elit libero, a pharetra augue. Vestibulum id ligula porta felis euismod semper. Cras justo odio, dapibus ac facilisis in, egestas eget quam. 72 | 73 |

74 |

75 | Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed posuere consectetur est at lobortis. Donec id elit non mi porta gravida at eget metus. Aenean lacinia bibendum nulla sed consectetur. 76 | 77 |

78 |

79 | Sed posuere consectetur est at lobortis. Cras mattis consectetur purus sit amet fermentum. Etiam porta sem malesuada magna mollis euismod. Donec id elit non mi porta gravida at eget metus. Etiam porta sem malesuada magna mollis euismod. 80 |

81 |

82 | Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Nulla vitae elit libero, a pharetra augue. Vestibulum id ligula porta felis euismod semper. Cras justo odio, dapibus ac facilisis in, egestas eget quam. 83 |

84 |
85 |
86 |
87 | 88 |
89 |
90 |
91 |

And me, and me!

92 |

This div is activated by element class - .multiple

93 |
94 |

95 | Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. 96 |

97 |

98 | Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed posuere consectetur est at lobortis. Donec id elit non mi porta gravida at eget metus. Aenean lacinia bibendum nulla sed consectetur. 99 |

100 |

101 | Sed posuere consectetur est at lobortis. Cras mattis consectetur purus sit amet fermentum. Etiam porta sem malesuada magna mollis euismod. Donec id elit non mi porta gravida at eget metus. Etiam porta sem malesuada magna mollis euismod. 102 | 103 |

104 |

One more header

105 |

106 | Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Nulla vitae elit libero, a pharetra augue. Vestibulum id ligula porta felis euismod semper. Cras justo odio, dapibus ac facilisis in, egestas eget quam. 107 | 108 |

109 |

110 | Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed posuere consectetur est at lobortis. Donec id elit non mi porta gravida at eget metus. Aenean lacinia bibendum nulla sed consectetur. 111 | 112 |

113 |

114 | Sed posuere consectetur est at lobortis. Cras mattis consectetur purus sit amet fermentum. Etiam porta sem malesuada magna mollis euismod. Donec id elit non mi porta gravida at eget metus. Etiam porta sem malesuada magna mollis euismod. 115 |

116 |

117 | Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Nulla vitae elit libero, a pharetra augue. Vestibulum id ligula porta felis euismod semper. Cras justo odio, dapibus ac facilisis in, egestas eget quam. 118 |

119 |
120 |
121 |
122 | 123 |
124 |
125 | 126 | 127 | 128 | 129 | 130 | 131 | --------------------------------------------------------------------------------