├── .gitignore ├── gulpfile.js ├── package.json ├── LICENSE ├── tests ├── test1 │ ├── slimscroll.css │ └── index.html └── test2 │ └── index.html ├── README.md ├── dist ├── slimscroll.min.js └── slimscroll.js └── src └── slimscroll.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var minify = require('gulp-minify'); 2 | var gulp = require('gulp'); 3 | 4 | gulp.task('default', function() { 5 | gulp.src('src/*.js') 6 | .pipe(minify({ 7 | ext:{ 8 | src:'.js', 9 | min:'.min.js' 10 | }, 11 | exclude: ['tasks'], 12 | ignoreFiles: ['.combo.js', '-min.js'] 13 | })) 14 | .pipe(gulp.dest('dist')) 15 | }); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "slim-scroll", 3 | "version": "1.3.2", 4 | "description": "Slim scroll is a replacement of default scrollbar provided by browsers on Windows. This library lets you design the scroll-bar by using simple css properties. It is created using javascript and css.", 5 | "main": "slimscroll.js", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "scripts": { 10 | "test": "echo \"Error: no test specified\" && exit 1" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/kamlekar/slim-scroll.git" 15 | }, 16 | "keywords": [ 17 | "slimscroll", 18 | "javascript", 19 | "slim", 20 | "scroll" 21 | ], 22 | "author": "Kamlekar", 23 | "license": "MIT", 24 | "bugs": { 25 | "url": "https://github.com/kamlekar/slim-scroll/issues" 26 | }, 27 | "homepage": "https://github.com/kamlekar/slim-scroll#readme", 28 | "devDependencies": { 29 | "gulp": "^3.9.1", 30 | "gulp-minify": "^2.1.0" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Mr_Green 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /tests/test1/slimscroll.css: -------------------------------------------------------------------------------- 1 | /* Demo css classes */ 2 | html, body{ 3 | height: 100%; 4 | } 5 | :focus{ 6 | outline: none; 7 | } 8 | .slimScroll { 9 | border: 1px solid #CCC; 10 | margin-top: 20px; 11 | display: inline-block; 12 | overflow: hidden; 13 | position: relative; 14 | height: 200px; /* set this height in percentage to test resizing */ 15 | width: 380px; 16 | } 17 | 18 | /* custom stylings */ 19 | .wrapper, .scroll-wrapper { 20 | padding: 5px; 21 | } 22 | .scroll-wrapper.mac + .scrollBarContainer{ 23 | background-color: transparent; 24 | } 25 | .scrollBarContainer.animate .scroll{ 26 | transition: 2s opacity ease; 27 | -ms-transition: 2s opacity ease; 28 | opacity: 0; 29 | } 30 | .scrollBarContainer:hover .scroll{ 31 | opacity: 0.5; 32 | transition: none; 33 | -ms-transition: none; 34 | } 35 | .unselectable { 36 | -webkit-user-select: none; 37 | -khtml-user-select: none; 38 | -moz-user-select: -moz-none; 39 | -o-user-select: none; 40 | user-select: none; 41 | } 42 | 43 | .scroll{ 44 | border-radius: 10px; 45 | } 46 | .wrapper + .scrollBarContainer{ 47 | background-color: #eee9ee; 48 | } 49 | .scrollBar { 50 | background-color: #60F509; 51 | border-radius: 10px; 52 | opacity: 0.5; 53 | } 54 | .scroll-bar{ 55 | background-color: #14D1E0; 56 | } 57 | -------------------------------------------------------------------------------- /tests/test2/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | slim scroll demo 7 | 8 | 9 | 20 | 21 | 22 |

Scroller Test

23 | 24 | 25 |
26 | 36 |
37 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Slim-scroll (_JavaScript Scroll Library_) ~ 4KB compressed 2 | 3 | Slim scroll is a replacement of default scrollbar provided by browsers on Windows. This library lets you design the scroll-bar by using simple css properties. It is created using javascript and css. 4 | 5 | [Download](https://github.com/kamlekar/slim-scroll/releases/latest)  |  [Github](https://github.com/venkateshwar/slim-scroll/)  |  [Demo](https://rawgit.com/venkateshwar/slim-scroll/master/tests/test1/index.html)   |   [CDNjs](https://cdnjs.com/libraries/slim-scroll) 6 | 7 | ### [Buy me a :beer: or :coffee:](https://paypal.me/kamlekar) 8 | 9 | **Tested on**: IE9+, Chrome and Firefox. 10 | 11 | ## 12 | 13 | ### Main Features: 14 | - Easier to color the custom scrollbar using CSS. 15 | - Can animate easily (_check below properties for support_). 16 | - Re-evaluates when the container is fluid, vertically. 17 | 18 | ### How to use: 19 | - To make it work, include `slimscroll.js` in `head` tag. 20 | - Apply height to the container in fixed units or percentage. 21 | - Just design the scrollbar as you want by applying css classes as explained below. 22 | - [In IE8] Apply high specificity to override normal styles given to the scroll bar. 23 | 24 | and then: 25 | 26 | ##### Method 1 (_with no added styles_): 27 | 28 | new slimScroll(Element); // 'Element' is Javascript DOM object 29 | 30 | ##### Method 2 (_with added styles_): 31 | 32 | or to add your own defined css styles: 33 | 34 | new slimScroll(Element, { 35 | 'wrapperClass': '', 36 | 37 | 'scrollBarClass': '', 38 | 39 | 'scrollBarContainerClass': '', 40 | 41 | 'scrollBarContainerSpecialClass': '', 42 | 43 | 'scrollBarMinHeight': '', 44 | 45 | 'scrollBarFixedHeight': '', 46 | 47 | 'keepFocus': true/false 48 | }); 49 | 50 | ##### Explanation of above properties: 51 | 52 | - **wrapperClass** (*type - "string"*) : Mention wrapper class here. 53 | - **scrollBarClass** (*type - "string"*) : Mention scroll bar class here. 54 | - **scrollBarContainerClass** (*type - "string"*) : Mention scroll bar container class here. 55 | - **scrollBarContainerSpecialClass** (*type - "string"*) : This property is used to mention a class which will be applied only when the user is scrolling the content. Could be helpful while applying animations to the scroll bar. 56 | - **scrollBarMinHeight** (*type - "Integer"*) : Used to mention minimum scroll bar height here (without pixel unit) 57 | - **scrollBarFixedHeight** (*type - "Integer"*) : Used to mention scroll bar fixed height (without pixel unit). This makes sure to show the scroll bar height fixed even when content inside the container is increased. 58 | - **keepFocus** (*type - "Boolean"*) : Used to focus the container. 59 | 60 | ### To make this work on height resize: 61 | 62 | var customScroll = new slimScroll(); 63 | window.onresize = customScroll.resetValues; // pure javascript example. 64 | 65 | ### Note: 66 | 67 | - Usage of the above mentioned properties is optional or as per need. 68 | - Add [higher specificity](https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity) css to override the custom styles which are being applied by this library. 69 | - Don't override the styles which are given highest specificity (`!important`) by this library (_those styles are necessary to make this scroll library work_). 70 | 71 | 72 | ### How I got this thought: 73 | 74 | I got this thought, when I found solution to hide the default scrollbar (_using css_) which was the requirement for a post on [Stackoverflow](http://stackoverflow.com/a/16671476/1577396). 75 | 76 | The solution was simple but that is how I got this thought :). 77 | 78 | ### Future implementations: 79 | - Implement Horizontal Scrollbar. 80 | 81 | --------------------------------- 82 | 83 | If you find any issue(s), please file [here](https://github.com/venkateshwar/slim-scroll/issues). 84 | -------------------------------------------------------------------------------- /dist/slimscroll.min.js: -------------------------------------------------------------------------------- 1 | var slimScroll=function(e,t){var n={},o=this,i="wrapper",r="scrollBar",s="scrollBarContainer",l="data-slimscroll",a="scrollTop",c="parentElement",u="innerHTML",d="parentNode",p="srcElement",f=function(e){if(o.initInProcess||(o.initDone||o.init(),B(n[i]))){n[i].setAttribute("style","overflow: hidden !important");var t=n.E;n.h=n[s].offsetHeight,n.sH=n[i].scrollHeight,n.sP=n.h/n.sH*100,n.sbh=n.sP*n.h/100,t.sH?n.sP1=t.sH/n.h*100:n.sP1=n.sbhn.rP1?u=n.rP1:u<0&&(u=0),n[r].style.top=u+"%",n[i][a]=u*n.sH1,m(n[s],l.S+l.a)}},S=function(e){var t=window.getSelection?window.getSelection():document.selection;t&&(t.removeAllRanges?t.removeAllRanges():t.empty&&t.empty());(e=e||event).currentTarget||e[p];return w("mousemove",document,x),w("mouseup",document,P),n.offsetTop=T(n[i]),n.firstY=e.pageY||event.clientY,n.reposition||(n.reposition=H(n[r],n.h)),!1},H=function(e,t){var n=parseInt(e.style.top.replace("%",""),10)*t/100;return n||0},x=function(e){var e=e||event,t=n.E,o=e.pageY||e.clientY,l=(n.reposition+o-n.firstY)/n.h*100;n.rP1=0&&n.firstY>n.offsetTop;(n.previousTop>l&&c||c&&n[i][a]+n.h!==n.sH)&&(n[r].style.top=l+"%",n.previousTop=l,n[i][a]=l*n.sH1),m(n[s],t.S)},P=function(e){var e=e||event,t=n.E;b("mousemove",document),b("mouseup",document),n.reposition=0,m(n[s],t.S+t.a)},y=function(e){e=e||event;if(n){var t=n.E;m(n[s],t.S),n[r].style.top=n[i][a]/n.sH1+"%",m(n[s],t.S+t.a)}},w=function(e,t,n){t["on"+e]=n},b=function(e,t){t["on"+e]=null},C=function(e,t,n,o){e.insertRule?e.insertRule(t+"{"+n+"}",o):e.addRule&&e.addRule(t,n,o)},T=function(e){var t=document.documentElement[a];return e.getBoundingClientRect().top+(t||document.body[a])},E=function(){if(e.removeAttribute(l),o.isSlimScrollInserted){var t=e.firstChild.innerHTML;t&&(e.innerHTML=t)}o.isSlimScrollInserted=!1,o.initDone=!1},B=function(t){return t||(t=e),t.offsetHeightdiv",i,0),C(u,e+">div+div",r,0),C(u,"[data-scrollbar]",s,0)):a.styleSheet.cssText=e+">div{"+i+"}"+e+">div+div{"+r+"}"+e+">div+div>div{"+s+"}",o.isSlimScrollInserted=!0,window.slimScrollStylesApplied=!0}}();var a=e[u],c=n.E={};t=t||{},c.w=t.wrapperClass||"",c.s=t.scrollBarClass||"",c.S=t.scrollBarContainerClass||"",c.a=t.scrollBarContainerSpecialClass?" "+t.scrollBarContainerSpecialClass:"",c.mH=t.scrollBarMinHeight||25,c.sH=t.scrollBarFixedHeight,e[u]="",n[i]=h(c.w,a,e),n[s]=h(c.S+c.a,"",e),n[r]=h(c.s,"",n[s]),v(n[r],"data-scrollbar","1"),f(),Y(),t.keepFocus&&(v(n[i],"tabindex","-1"),n[i].focus()),w("mousedown",n[r],S),w("click",n[s],g),w("scroll",n[i],y),o.initInProcess=!1}else E()},Y=function(){n[i].style.overflow="";var e=n[i].offsetWidth-n[i].clientWidth;n[i].style.right=-e+"px",o.isSlimScrollInserted=!0,t.keepFocus&&(v(n[i],"tabindex","-1"),n[i].focus())};return o.resetValues=function(){Object.keys(n).length?(f(),Y()):f()},o.init=I,I(),o}; -------------------------------------------------------------------------------- /tests/test1/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | slim scroll demo 7 | 8 | 9 | 48 | 49 | 50 | Visit Website 51 |
52 |
53 | Lorem ipsum dolor sit amet, ne eos utinam impetus legimus, vide omnis nusquam eam te. Impetus mediocritatem eu mea. Nisl oblique salutandi no cum. Ei pro everti periculis. Ne per ignota delenit, vis officiis indoctum urbanitas no, accusata torquatos incorrupte at per. At mei soluta sanctus contentiones, eam id sint molestie scriptorem. An tation contentiones eum. Nec id offendit facilisi, ex eligendi gubergren eum, ne libris commune est. Modus labitur patrioque quo cu, eu mei altera integre eleifend, ea quod abhorreant vix. Per eu errem saepe nusquam. Ne congue splendide vim, pri ad vocibus omittam assentior. Cu nam eirmod ocurreret, partem intellegam est et. Illum aliquam legendos at sed, ne idque fastidii apeirian vix. Sed nisl libris delectus ei. Percipit oporteat philosophia et vel, liber deterruisset eu his, paulo mentitum te his. Et duo paulo iudicabit, voluptua placerat ea mei. Quo ea ponderum omittantur referrentur. At homero bonorum nominati has, suas comprehensam eum in. At meis lobortis cum. Diam ipsum consulatu pro no, wisi nullam labores mel an, pro error integre molestiae te. Scripta accommodare sea in, has ne error viris. Erat qualisque eu vim, an atqui vivendo forensibus usu. Iisque petentium ad cum. 54 | Lorem ipsum dolor sit amet, ne eos utinam impetus legimus, vide omnis nusquam eam te. Impetus mediocritatem eu mea. Nisl oblique salutandi no cum. Ei pro everti periculis. Ne per ignota delenit, vis officiis indoctum urbanitas no, accusata torquatos incorrupte at per. At mei soluta sanctus contentiones, eam id sint molestie scriptorem. An tation contentiones eum. Nec id offendit facilisi, ex eligendi gubergren eum, ne libris commune est. Modus labitur patrioque quo cu, eu mei altera integre eleifend, ea quod abhorreant vix. Per eu errem saepe nusquam. Ne congue splendide vim, pri ad vocibus omittam assentior. Cu nam eirmod ocurreret, partem intellegam est et. Illum aliquam legendos at sed, ne idque fastidii apeirian vix. Sed nisl libris delectus ei. Percipit oporteat philosophia et vel, liber deterruisset eu his, paulo mentitum te his. Et duo paulo iudicabit, voluptua placerat ea mei. Quo ea ponderum omittantur referrentur. At homero bonorum nominati has, suas comprehensam eum in. At meis lobortis cum. Diam ipsum consulatu pro no, wisi nullam labores mel an, pro error integre molestiae te. Scripta accommodare sea in, has ne error viris. Erat qualisque eu vim, an atqui vivendo forensibus usu. Iisque petentium ad cum. 55 |
56 | 57 |
58 | Lorem ipsum dolor sit amet, ne eos utinam impetus legimus, vide omnis nusquam eam te. Impetus mediocritatem eu mea. Nisl oblique salutandi no cum. Ei pro everti periculis. Ne per ignota delenit, vis officiis indoctum urbanitas no, accusata torquatos incorrupte at per. At mei soluta sanctus contentiones, eam id sint molestie scriptorem. An tation contentiones eum. Nec id offendit facilisi, ex eligendi gubergren eum, ne libris commune est. Modus labitur patrioque quo cu, eu mei altera integre eleifend, ea quod abhorreant vix. Per eu errem saepe nusquam. Ne congue splendide vim, pri ad vocibus omittam assentior. Cu nam eirmod ocurreret, partem intellegam est et. Illum aliquam legendos at sed, ne idque fastidii apeirian vix. Sed nisl libris delectus ei. Percipit oporteat philosophia et vel, liber deterruisset eu his, paulo mentitum te his. Et duo paulo iudicabit, voluptua placerat ea mei. Quo ea ponderum omittantur referrentur. At homero bonorum nominati has, suas comprehensam eum in. At meis lobortis cum. Diam ipsum consulatu pro no, wisi nullam labores mel an, pro error integre molestiae te. Scripta accommodare sea in, has ne error viris. Erat qualisque eu vim, an atqui vivendo forensibus usu. Iisque petentium ad cum. 59 | Lorem ipsum dolor sit amet, ne eos utinam impetus legimus, vide omnis nusquam eam te. Impetus mediocritatem eu mea. Nisl oblique salutandi no cum. Ei pro everti periculis. Ne per ignota delenit, vis officiis indoctum urbanitas no, accusata torquatos incorrupte at per. At mei soluta sanctus contentiones, eam id sint molestie scriptorem. An tation contentiones eum. Nec id offendit facilisi, ex eligendi gubergren eum, ne libris commune est. Modus labitur patrioque quo cu, eu mei altera integre eleifend, ea quod abhorreant vix. Per eu errem saepe nusquam. Ne congue splendide vim, pri ad vocibus omittam assentior. Cu nam eirmod ocurreret, partem intellegam est et. Illum aliquam legendos at sed, ne idque fastidii apeirian vix. Sed nisl libris delectus ei. Percipit oporteat philosophia et vel, liber deterruisset eu his, paulo mentitum te his. Et duo paulo iudicabit, voluptua placerat ea mei. Quo ea ponderum omittantur referrentur. At homero bonorum nominati has, suas comprehensam eum in. At meis lobortis cum. Diam ipsum consulatu pro no, wisi nullam labores mel an, pro error integre molestiae te. Scripta accommodare sea in, has ne error viris. Erat qualisque eu vim, an atqui vivendo forensibus usu. Iisque petentium ad cum. 60 |
61 | 62 |
63 | Lorem ipsum dolor sit amet, ne eos utinam impetus legimus, vide omnis nusquam eam te. Impetus mediocritatem eu mea. Nisl oblique salutandi no cum. Ei pro everti periculis. Ne per ignota delenit, vis officiis indoctum urbanitas no, accusata torquatos incorrupte at per. At mei soluta sanctus contentiones, eam id sint molestie scriptorem. An tation contentiones eum. Nec id offendit facilisi, ex eligendi gubergren eum, ne libris commune est. Modus labitur patrioque quo cu, eu mei altera integre eleifend, ea quod abhorreant vix. Per eu errem saepe nusquam. Ne congue splendide vim, pri ad vocibus omittam assentior. Cu nam eirmod ocurreret, partem intellegam est et. Illum aliquam legendos at sed, ne idque fastidii apeirian vix. Sed nisl libris delectus ei. Percipit oporteat philosophia et vel, liber deterruisset eu his, paulo mentitum te his. Et duo paulo iudicabit, voluptua placerat ea mei. Quo ea ponderum omittantur referrentur. At homero bonorum nominati has, suas comprehensam eum in. At meis lobortis cum. Diam ipsum consulatu pro no, wisi nullam labores mel an, pro error integre molestiae te. Scripta accommodare sea in, has ne error viris. Erat qualisque eu vim, an atqui vivendo forensibus usu. Iisque petentium ad cum. 64 | Lorem ipsum dolor sit amet, ne eos utinam impetus legimus, vide omnis nusquam eam te. Impetus mediocritatem eu mea. Nisl oblique salutandi no cum. Ei pro everti periculis. Ne per ignota delenit, vis officiis indoctum urbanitas no, accusata torquatos incorrupte at per. At mei soluta sanctus contentiones, eam id sint molestie scriptorem. An tation contentiones eum. Nec id offendit facilisi, ex eligendi gubergren eum, ne libris commune est. Modus labitur patrioque quo cu, eu mei altera integre eleifend, ea quod abhorreant vix. Per eu errem saepe nusquam. Ne congue splendide vim, pri ad vocibus omittam assentior. Cu nam eirmod ocurreret, partem intellegam est et. Illum aliquam legendos at sed, ne idque fastidii apeirian vix. Sed nisl libris delectus ei. Percipit oporteat philosophia et vel, liber deterruisset eu his, paulo mentitum te his. Et duo paulo iudicabit, voluptua placerat ea mei. Quo ea ponderum omittantur referrentur. At homero bonorum nominati has, suas comprehensam eum in. At meis lobortis cum. Diam ipsum consulatu pro no, wisi nullam labores mel an, pro error integre molestiae te. Scripta accommodare sea in, has ne error viris. Erat qualisque eu vim, an atqui vivendo forensibus usu. Iisque petentium ad cum. 65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /dist/slimscroll.js: -------------------------------------------------------------------------------- 1 | var slimScroll = function(C, payload){ 2 | var i = {}, 3 | _this = this, 4 | w = "wrapper", 5 | s = "scrollBar", 6 | S = "scrollBarContainer", 7 | a = "", 8 | m = "", 9 | l ="data-slimscroll", 10 | // properties 11 | oT = "offsetTop", 12 | sT = "scrollTop", 13 | pE = "parentElement", 14 | pes = "previousElementSibling", 15 | iH = "innerHTML", 16 | cT = "currentTarget", 17 | sK = "scroll-k", 18 | U = "%", 19 | d = ".", 20 | // IE8 properties 21 | // (Dev note: remove below variables from all over the code to exclude IE8 compatibility) 22 | pN = "parentNode", 23 | pS = "previousSibling", // Not used anywhere (need to check) 24 | sE = "srcElement", // Not used anywhere (need to check) 25 | assignValues = function(k){ 26 | if(!_this.initInProcess){ 27 | if(!_this.initDone){ // If i object is empty 28 | _this.init(); // Initialize again 29 | } 30 | 31 | if(!scrollBarVisible(i[w])){ 32 | removeSlimScroll(); 33 | return; 34 | } 35 | } 36 | 37 | // hide the scrollbar temporarily to take the calculations correctly 38 | i[w].setAttribute("style", "overflow: hidden !important"); 39 | var q = i.E; 40 | i.h = i[S].offsetHeight; 41 | i.sH = i[w].scrollHeight; 42 | i.sP = (i.h/i.sH) * 100; 43 | // i.sbh is scroll bar height in pixels without pixel unit. 44 | i.sbh = i.sP * i.h/100; 45 | // Manually set the height of the scrollbar (in percentage) 46 | // if user hasn't provided the fixed scroll height value 47 | if(!q.sH) i.sP1 = i.sbh < q.mH? (q.mH/i.h * 100): i.sP; 48 | else i.sP1 = q.sH/i.h * 100; 49 | 50 | i.rP1 = 100 - i.sP1; 51 | i.x = (i.sH - i.h) * ((i.sP1 - i.sP)/(100 - i.sP)); 52 | i.sH1 = Math.abs((i.x / (i.rP1)) + (i.sH/100)); 53 | i[s].style.height = i.sP1 + U; 54 | 55 | i.reposition = getReposition(i[s], i.h); 56 | }, 57 | // Start of private functions 58 | setAttr = function(e, p, v){ 59 | e.setAttribute(p,v); 60 | }, 61 | getAttr = function(e, p){ 62 | if(!e) return; 63 | return e.getAttribute(p); 64 | }, 65 | addClass = function(e, c){ 66 | if(c.length) e.className = c; 67 | }, 68 | cE = function(c, h, p){ 69 | var d = document.createElement('div'); 70 | addClass(d, c); 71 | d[iH] = h; 72 | p.appendChild(d); 73 | return d; 74 | }, 75 | setScroll = function(e){ 76 | var e = e || event,el = e.target || event[sE], 77 | p = el[pE] || el[pN]; 78 | var q = i.E; 79 | 80 | if(!i || p === i[S]) return; 81 | var eY = e.pageY || event.clientY, 82 | top = ((eY - getTop(i[w][pE] || i[w][pN]))/i.h * 100) - i.sP1/2; 83 | if(top > i.rP1) top = i.rP1; 84 | else if(top < 0) top = 0; 85 | i[s].style.top = top + U; 86 | i[w][sT] = top * i.sH1; 87 | addClass(i[S], q.S + q.a); 88 | }, 89 | beginScroll = function(e){ 90 | // removing selected text 91 | // Link: http://stackoverflow.com/a/3171348 92 | var sel = window.getSelection ? window.getSelection() : document.selection; 93 | if (sel) { 94 | if (sel.removeAllRanges) sel.removeAllRanges(); 95 | else if (sel.empty) sel.empty(); 96 | } 97 | var e = e || event, 98 | el = e[cT] || e[sE]; 99 | 100 | addEvent('mousemove', document, moveScroll); 101 | addEvent('mouseup', document, endScroll); 102 | 103 | i[oT] = getTop(i[w]); 104 | i.firstY = e.pageY || event.clientY; 105 | if(!i.reposition) i.reposition = getReposition(i[s], i.h); 106 | // Disable text selection while dragging the scrollbar 107 | return false; 108 | }, 109 | getReposition = function(i, h){ 110 | var x = parseInt(i.style.top.replace(U,""),10) * h/100; 111 | return x?x:0; 112 | }, 113 | moveScroll = function(e){ 114 | var e = e || event, 115 | q = i.E, 116 | eY = e.pageY || e.clientY, 117 | top = (i.reposition + eY - i.firstY)/i.h * 100; 118 | 119 | if(i.rP1 < top) top = i.rP1; 120 | if(!i.previousTop) i.previousTop = top + 1; 121 | var blnThreshold = top >= 0 && i.firstY > i[oT]; 122 | if((i.previousTop > top && blnThreshold) || (blnThreshold && (i[w][sT] + i.h !== i.sH))){ 123 | i[s].style.top = top + U; 124 | i.previousTop = top; 125 | i[w][sT] = top * i.sH1; 126 | } 127 | addClass(i[S], q.S); 128 | }, 129 | endScroll = function(e){ 130 | var e = e || event,q = i.E; 131 | 132 | removeEvent('mousemove', document); 133 | removeEvent('mouseup', document); 134 | 135 | i.reposition = 0; 136 | addClass(i[S], q.S + q.a); 137 | }, 138 | doScroll = function(e){ 139 | var e = e || event; 140 | if(!i) return; 141 | var q = i.E; 142 | addClass(i[S], q.S); 143 | i[s].style.top = i[w][sT]/i.sH1 + U; 144 | addClass(i[S], q.S + q.a); 145 | }, 146 | addEvent = function(e, el, func){ 147 | el['on' + e] = func; 148 | // el.addEventListener(e, func, false); 149 | }, 150 | removeEvent = function(e, el){ 151 | el['on' + e] = null; 152 | // el.removeEventListener(e, func, false); 153 | }, 154 | addCSSRule = function(S, s, r, i) { 155 | if(S.insertRule) S.insertRule(s + "{" + r + "}", i); 156 | else if(S.addRule) S.addRule(s, r, i); 157 | }, 158 | getTop = function(el){ 159 | var t = document.documentElement[sT]; 160 | return el.getBoundingClientRect().top + (t?t:document.body[sT]); 161 | }, 162 | insertCss = function(){ 163 | if(!window.slimScrollStylesApplied){ 164 | if(_this.isSlimScrollInserted){ 165 | _this.initInProcess = false; 166 | return; 167 | } 168 | // Inserting css rules 169 | // Link: http://davidwalsh.name/add-rules-stylesheets 170 | var slim = "["+l+"]", 171 | imp = " !important", 172 | pA = "position:absolute"+imp, 173 | // classes 174 | w = pA+";overflow:auto"+imp+";left:0px;top:0px"+imp+";right:0px;bottom:0px"+imp+";padding-right:8px"+imp+";", 175 | S = pA+";top:0px"+imp+";bottom:0px"+imp+";right:0px;left:auto;width:5px;cursor:pointer"+imp+";padding-right:0px"+imp+";", 176 | s = pA+";background-color:#999;top:0px;left:0px;right:0px;", 177 | //creating a sheet 178 | style = document.createElement('style'), 179 | scrollBar = "[data-scrollbar]"; 180 | try{ 181 | // WebKit hack :( 182 | style.appendChild(document.createTextNode("")); 183 | }catch(ex){} 184 | 185 | var head = document.head || document.getElementsByTagName('head')[0]; 186 | 187 | // adding above css to the sheet 188 | head.insertBefore(style, (head.hasChildNodes()) 189 | ? head.childNodes[0] 190 | : null); 191 | var sheet = style.sheet; 192 | if(sheet){ 193 | addCSSRule(sheet, slim+">div", w, 0); 194 | addCSSRule(sheet, slim+">div+div", S, 0); 195 | addCSSRule(sheet, scrollBar, s, 0); 196 | } 197 | else{ 198 | style.styleSheet.cssText = slim+">div{"+w+"}"+slim+">div+div"+"{"+S+"}"+slim+">div+div>div{"+s+"}"; 199 | } 200 | _this.isSlimScrollInserted = true; 201 | window.slimScrollStylesApplied = true; 202 | } 203 | }, 204 | removeSlimScroll = function(){ 205 | C.removeAttribute(l); //reset 206 | if(_this.isSlimScrollInserted){ 207 | var insideContent = C.firstChild.innerHTML; 208 | if(insideContent){ 209 | C.innerHTML = insideContent; 210 | } 211 | } 212 | _this.isSlimScrollInserted = false; 213 | _this.initDone = false; 214 | 215 | }, 216 | scrollBarVisible = function(x){ 217 | if(!x) x = C; 218 | return x.offsetHeight < x.scrollHeight; 219 | }, 220 | // Initial function 221 | init = function(){ 222 | removeSlimScroll(); 223 | if(scrollBarVisible()){ 224 | _this.initDone = true; 225 | _this.initInProcess = true; 226 | setAttr(C, l, '1'); 227 | insertCss(); 228 | var h = C[iH], q = i.E = {}; 229 | // setting user defined classes 230 | payload = payload || {}; 231 | q.w = payload.wrapperClass || ""; 232 | q.s = payload.scrollBarClass || ""; 233 | q.S = payload.scrollBarContainerClass || ""; 234 | q.a = payload.scrollBarContainerSpecialClass ? " " + payload.scrollBarContainerSpecialClass : ""; 235 | q.mH = payload.scrollBarMinHeight || 25; 236 | q.sH = payload.scrollBarFixedHeight; // could be undefined 237 | 238 | C[iH] = ""; 239 | i[w] = cE(q.w, h, C); 240 | i[S] = cE(q.S + q.a, "", C); 241 | i[s] = cE(q.s, "", i[S]); 242 | setAttr(i[s], 'data-scrollbar', '1'); 243 | assignValues(); 244 | 245 | placeIt(); 246 | if(payload.keepFocus){ 247 | setAttr(i[w], 'tabindex', '-1'); 248 | i[w].focus(); 249 | } 250 | // Attaching mouse events 251 | addEvent('mousedown', i[s], beginScroll); 252 | addEvent('click', i[S], setScroll); 253 | // For scroll 254 | addEvent('scroll', i[w], doScroll); 255 | // addEvent('selectstart', i[S], function(){return;}); 256 | _this.initInProcess = false; 257 | } 258 | else{ 259 | removeSlimScroll(); 260 | return; // don't do any further operations 261 | } 262 | }, 263 | 264 | placeIt = function(){ 265 | // Show the default scrollbar to get the scrollbar width 266 | i[w].style.overflow = ""; 267 | var scrollBarWidth = i[w].offsetWidth - i[w].clientWidth; 268 | // Stretching the inner container so that the default scrollbar is completely invisible 269 | i[w].style.right = -scrollBarWidth + "px"; 270 | _this.isSlimScrollInserted = true; 271 | if(payload.keepFocus){ 272 | setAttr(i[w], 'tabindex', '-1'); 273 | i[w].focus(); 274 | } 275 | }; 276 | 277 | _this.resetValues = function(){ 278 | if(Object.keys(i).length){ 279 | assignValues(); 280 | 281 | placeIt(); 282 | } 283 | else{ 284 | assignValues(); 285 | } 286 | } 287 | _this.init = init; 288 | init(); 289 | return _this; 290 | }; 291 | -------------------------------------------------------------------------------- /src/slimscroll.js: -------------------------------------------------------------------------------- 1 | var slimScroll = function(C, payload){ 2 | var i = {}, 3 | _this = this, 4 | w = "wrapper", 5 | s = "scrollBar", 6 | S = "scrollBarContainer", 7 | a = "", 8 | m = "", 9 | l ="data-slimscroll", 10 | // properties 11 | oT = "offsetTop", 12 | sT = "scrollTop", 13 | pE = "parentElement", 14 | pes = "previousElementSibling", 15 | iH = "innerHTML", 16 | cT = "currentTarget", 17 | sK = "scroll-k", 18 | U = "%", 19 | d = ".", 20 | // IE8 properties 21 | // (Dev note: remove below variables from all over the code to exclude IE8 compatibility) 22 | pN = "parentNode", 23 | pS = "previousSibling", // Not used anywhere (need to check) 24 | sE = "srcElement", // Not used anywhere (need to check) 25 | assignValues = function(k){ 26 | if(!_this.initInProcess){ 27 | if(!_this.initDone){ // If i object is empty 28 | _this.init(); // Initialize again 29 | } 30 | 31 | if(!scrollBarVisible(i[w])){ 32 | removeSlimScroll(); 33 | return; 34 | } 35 | } 36 | 37 | // hide the scrollbar temporarily to take the calculations correctly 38 | i[w].setAttribute("style", "overflow: hidden !important"); 39 | var q = i.E; 40 | i.h = i[S].offsetHeight; 41 | i.sH = i[w].scrollHeight; 42 | i.sP = (i.h/i.sH) * 100; 43 | // i.sbh is scroll bar height in pixels without pixel unit. 44 | i.sbh = i.sP * i.h/100; 45 | // Manually set the height of the scrollbar (in percentage) 46 | // if user hasn't provided the fixed scroll height value 47 | if(!q.sH) i.sP1 = i.sbh < q.mH? (q.mH/i.h * 100): i.sP; 48 | else i.sP1 = q.sH/i.h * 100; 49 | 50 | i.rP1 = 100 - i.sP1; 51 | i.x = (i.sH - i.h) * ((i.sP1 - i.sP)/(100 - i.sP)); 52 | i.sH1 = Math.abs((i.x / (i.rP1)) + (i.sH/100)); 53 | i[s].style.height = i.sP1 + U; 54 | 55 | i.reposition = getReposition(i[s], i.h); 56 | }, 57 | // Start of private functions 58 | setAttr = function(e, p, v){ 59 | e.setAttribute(p,v); 60 | }, 61 | getAttr = function(e, p){ 62 | if(!e) return; 63 | return e.getAttribute(p); 64 | }, 65 | addClass = function(e, c){ 66 | if(c.length) e.className = c; 67 | }, 68 | cE = function(c, h, p){ 69 | var d = document.createElement('div'); 70 | addClass(d, c); 71 | d[iH] = h; 72 | p.appendChild(d); 73 | return d; 74 | }, 75 | setScroll = function(e){ 76 | var e = e || event,el = e.target || event[sE], 77 | p = el[pE] || el[pN]; 78 | var q = i.E; 79 | 80 | if(!i || p === i[S]) return; 81 | var eY = e.pageY || event.clientY, 82 | top = ((eY - getTop(i[w][pE] || i[w][pN]))/i.h * 100) - i.sP1/2; 83 | if(top > i.rP1) top = i.rP1; 84 | else if(top < 0) top = 0; 85 | i[s].style.top = top + U; 86 | i[w][sT] = top * i.sH1; 87 | addClass(i[S], q.S + q.a); 88 | }, 89 | beginScroll = function(e){ 90 | // removing selected text 91 | // Link: http://stackoverflow.com/a/3171348 92 | var sel = window.getSelection ? window.getSelection() : document.selection; 93 | if (sel) { 94 | if (sel.removeAllRanges) sel.removeAllRanges(); 95 | else if (sel.empty) sel.empty(); 96 | } 97 | var e = e || event, 98 | el = e[cT] || e[sE]; 99 | 100 | addEvent('mousemove', document, moveScroll); 101 | addEvent('mouseup', document, endScroll); 102 | 103 | i[oT] = getTop(i[w]); 104 | i.firstY = e.pageY || event.clientY; 105 | if(!i.reposition) i.reposition = getReposition(i[s], i.h); 106 | // Disable text selection while dragging the scrollbar 107 | return false; 108 | }, 109 | getReposition = function(i, h){ 110 | var x = parseInt(i.style.top.replace(U,""),10) * h/100; 111 | return x?x:0; 112 | }, 113 | moveScroll = function(e){ 114 | var e = e || event, 115 | q = i.E, 116 | eY = e.pageY || e.clientY, 117 | top = (i.reposition + eY - i.firstY)/i.h * 100; 118 | 119 | if(i.rP1 < top) top = i.rP1; 120 | if(!i.previousTop) i.previousTop = top + 1; 121 | var blnThreshold = top >= 0 && i.firstY > i[oT]; 122 | if((i.previousTop > top && blnThreshold) || (blnThreshold && (i[w][sT] + i.h !== i.sH))){ 123 | i[s].style.top = top + U; 124 | i.previousTop = top; 125 | i[w][sT] = top * i.sH1; 126 | } 127 | addClass(i[S], q.S); 128 | }, 129 | endScroll = function(e){ 130 | var e = e || event,q = i.E; 131 | 132 | removeEvent('mousemove', document); 133 | removeEvent('mouseup', document); 134 | 135 | i.reposition = 0; 136 | addClass(i[S], q.S + q.a); 137 | }, 138 | doScroll = function(e){ 139 | var e = e || event; 140 | if(!i) return; 141 | var q = i.E; 142 | addClass(i[S], q.S); 143 | i[s].style.top = i[w][sT]/i.sH1 + U; 144 | addClass(i[S], q.S + q.a); 145 | }, 146 | addEvent = function(e, el, func){ 147 | el['on' + e] = func; 148 | // el.addEventListener(e, func, false); 149 | }, 150 | removeEvent = function(e, el){ 151 | el['on' + e] = null; 152 | // el.removeEventListener(e, func, false); 153 | }, 154 | addCSSRule = function(S, s, r, i) { 155 | if(S.insertRule) S.insertRule(s + "{" + r + "}", i); 156 | else if(S.addRule) S.addRule(s, r, i); 157 | }, 158 | getTop = function(el){ 159 | var t = document.documentElement[sT]; 160 | return el.getBoundingClientRect().top + (t?t:document.body[sT]); 161 | }, 162 | insertCss = function(){ 163 | if(!window.slimScrollStylesApplied){ 164 | if(_this.isSlimScrollInserted){ 165 | _this.initInProcess = false; 166 | return; 167 | } 168 | // Inserting css rules 169 | // Link: http://davidwalsh.name/add-rules-stylesheets 170 | var slim = "["+l+"]", 171 | imp = " !important", 172 | pA = "position:absolute"+imp, 173 | // classes 174 | w = pA+";overflow:auto"+imp+";left:0px;top:0px"+imp+";right:0px;bottom:0px"+imp+";padding-right:8px"+imp+";", 175 | S = pA+";top:0px"+imp+";bottom:0px"+imp+";right:0px;left:auto;width:5px;cursor:pointer"+imp+";padding-right:0px"+imp+";", 176 | s = pA+";background-color:#999;top:0px;left:0px;right:0px;", 177 | //creating a sheet 178 | style = document.createElement('style'), 179 | scrollBar = "[data-scrollbar]"; 180 | try{ 181 | // WebKit hack :( 182 | style.appendChild(document.createTextNode("")); 183 | }catch(ex){} 184 | 185 | var head = document.head || document.getElementsByTagName('head')[0]; 186 | 187 | // adding above css to the sheet 188 | head.insertBefore(style, (head.hasChildNodes()) 189 | ? head.childNodes[0] 190 | : null); 191 | var sheet = style.sheet; 192 | if(sheet){ 193 | addCSSRule(sheet, slim+">div", w, 0); 194 | addCSSRule(sheet, slim+">div+div", S, 0); 195 | addCSSRule(sheet, scrollBar, s, 0); 196 | } 197 | else{ 198 | style.styleSheet.cssText = slim+">div{"+w+"}"+slim+">div+div"+"{"+S+"}"+slim+">div+div>div{"+s+"}"; 199 | } 200 | _this.isSlimScrollInserted = true; 201 | window.slimScrollStylesApplied = true; 202 | } 203 | }, 204 | removeSlimScroll = function(){ 205 | C.removeAttribute(l); //reset 206 | if(_this.isSlimScrollInserted){ 207 | var insideContent = C.firstChild.innerHTML; 208 | if(insideContent){ 209 | C.innerHTML = insideContent; 210 | } 211 | } 212 | _this.isSlimScrollInserted = false; 213 | _this.initDone = false; 214 | 215 | }, 216 | scrollBarVisible = function(x){ 217 | if(!x) x = C; 218 | return x.offsetHeight < x.scrollHeight; 219 | }, 220 | // Initial function 221 | init = function(){ 222 | removeSlimScroll(); 223 | if(scrollBarVisible()){ 224 | _this.initDone = true; 225 | _this.initInProcess = true; 226 | setAttr(C, l, '1'); 227 | insertCss(); 228 | var h = C[iH], q = i.E = {}; 229 | // setting user defined classes 230 | payload = payload || {}; 231 | q.w = payload.wrapperClass || ""; 232 | q.s = payload.scrollBarClass || ""; 233 | q.S = payload.scrollBarContainerClass || ""; 234 | q.a = payload.scrollBarContainerSpecialClass ? " " + payload.scrollBarContainerSpecialClass : ""; 235 | q.mH = payload.scrollBarMinHeight || 25; 236 | q.sH = payload.scrollBarFixedHeight; // could be undefined 237 | 238 | C[iH] = ""; 239 | i[w] = cE(q.w, h, C); 240 | i[S] = cE(q.S + q.a, "", C); 241 | i[s] = cE(q.s, "", i[S]); 242 | setAttr(i[s], 'data-scrollbar', '1'); 243 | assignValues(); 244 | 245 | placeIt(); 246 | if(payload.keepFocus){ 247 | setAttr(i[w], 'tabindex', '-1'); 248 | i[w].focus(); 249 | } 250 | // Attaching mouse events 251 | addEvent('mousedown', i[s], beginScroll); 252 | addEvent('click', i[S], setScroll); 253 | // For scroll 254 | addEvent('scroll', i[w], doScroll); 255 | // addEvent('selectstart', i[S], function(){return;}); 256 | _this.initInProcess = false; 257 | } 258 | else{ 259 | removeSlimScroll(); 260 | return; // don't do any further operations 261 | } 262 | }, 263 | 264 | placeIt = function(){ 265 | // Show the default scrollbar to get the scrollbar width 266 | i[w].style.overflow = ""; 267 | var scrollBarWidth = i[w].offsetWidth - i[w].clientWidth; 268 | // Stretching the inner container so that the default scrollbar is completely invisible 269 | i[w].style.right = -scrollBarWidth + "px"; 270 | _this.isSlimScrollInserted = true; 271 | if(payload.keepFocus){ 272 | setAttr(i[w], 'tabindex', '-1'); 273 | i[w].focus(); 274 | } 275 | }; 276 | 277 | _this.resetValues = function(){ 278 | if(Object.keys(i).length){ 279 | assignValues(); 280 | 281 | placeIt(); 282 | } 283 | else{ 284 | assignValues(); 285 | } 286 | } 287 | _this.init = init; 288 | init(); 289 | return _this; 290 | }; 291 | --------------------------------------------------------------------------------