Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. If you link to another Pen, it will include the CSS from that Pen. If the preprocessor matches, it will attempt to combine them before processing.

+ add another resource

JavaScript

Babel is required to process package imports. If you need a different preprocessor remove all packages first.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Behavior

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                <h1>Smart Scrollbar Example</h1>

<div id="container">Lorem ipsum dolor sit amet, te eos facilis noluisse consetetur. Ei quodsi labitur vulputate vix. Vix no nisl ornatus, discere consequat te mea. Cu ius quem ferri assueverit, cu sit nulla persequeris concludaturque. Vim ut sale causae referrentur.

    Id habemus pertinacia ius, mea fastidii convenire at. At sit postulant repudiandae, has ut natum delicatissimi. Quo liber veritus ponderum ea, his cu corrumpit consequuntur. Et cum apeirian percipitur, invidunt salutatus ex ius. Mea exerci conceptam ad, at vim accusata adipiscing.

    Nam decore docendi cu, vide liber accusam eam ei, at quando malorum sapientem vis. Eam te hinc facer. Eu usu option intellegat, cibo debitis graecis sed ei, consul tempor id pri. Quo at dicam electram, qui ut nonumy nonumes constituam. Eos nibh quaestio efficiendi an, munere argumentum ei vix, ex cum nisl novum gubergren. Vix in veniam propriae, labitur sadipscing eu mel.

Qui ut ubique placerat euripidis. His esse eius ne, ut docendi gloriatur posidonium quo. Et inermis ceteros ius, ea pro novum ignota vivendo. Cum id vide laudem, augue inermis definitiones mea at, phaedrum dissentiunt te per.

Conceptam ullamcorper an mea, autem idque pri in. Duo homero delenit no, aperiri aliquando ei vel, scripta interesset usu ut. Iriure aliquip vivendum an sit, mea molestie consulatu democritum ne, in vix virtute vivendo petentium. Vix an habeo partem ullamcorper, in mei dissentiunt concludaturque. Ipsum accusata incorrupte vix an, an sed ferri tritani voluptatibus.

Putent nostrud in ius, dicta consectetuer has ex. Ad tota graeco comprehensam pri, usu reque nobis aliquando ut. Eam ut viderer quaestio accusamus, audire menandri conclusionemque ex vim. Ius ex solet fuisset, ei dicta iudico mel. No eum vivendo volutpat expetenda, menandri iracundia ea vim.

Fugit detracto liberavisse vel an, has an amet accusam. Mei facer intellegam te, nec forensibus adipiscing ex. Iusto aperiri an his. Ei cum bonorum dolorum, enim atqui ex cum.

Invenire interpretaris ei pri, omnes tantas vidisse at ius, essent vidisse et mel. Illud partiendo referrentur cu has, aliquip impedit vim no. Ex mel veritus antiopam. Habeo utinam quidam per ne. Dolorem ancillae vim ex, te quidam ornatus propriae duo. Dictas eripuit ex eam, ut reque choro maluisset usu.

An debet inermis eam. Mei dicit munere ex. Posse disputando et per. In mundi iuvaret evertitur nec, cu simul impedit volumus mel. His meis vidisse adolescens at.

Cibo placerat maiestatis ne est, vix ad mollis civibus dolores, nemore nostro sed no. No decore tempor persecuti eum, eirmod inermis laboramus no mei. Ei suas euripidis honestatis vis. Impedit singulis corrumpit nec ex. At duo sint delicata, ea justo dolor per.
    
    Lorem ipsum dolor sit amet, te eos facilis noluisse consetetur. Ei quodsi labitur vulputate vix. Vix no nisl ornatus, discere consequat te mea. Cu ius quem ferri assueverit, cu sit nulla persequeris concludaturque. Vim ut sale causae referrentur.

Id habemus pertinacia ius, mea fastidii convenire at. At sit postulant repudiandae, has ut natum delicatissimi. Quo liber veritus ponderum ea, his cu corrumpit consequuntur. Et cum apeirian percipitur, invidunt salutatus ex ius. Mea exerci conceptam ad, at vim accusata adipiscing.

Nam decore docendi cu, vide liber accusam eam ei, at quando malorum sapientem vis. Eam te hinc facer. Eu usu option intellegat, cibo debitis graecis sed ei, consul tempor id pri. Quo at dicam electram, qui ut nonumy nonumes constituam. Eos nibh quaestio efficiendi an, munere argumentum ei vix, ex cum nisl novum gubergren. Vix in veniam propriae, labitur sadipscing eu mel.

Qui ut ubique placerat euripidis. His esse eius ne, ut docendi gloriatur posidonium quo. Et inermis ceteros ius, ea pro novum ignota vivendo. Cum id vide laudem, augue inermis definitiones mea at, phaedrum dissentiunt te per.

Conceptam ullamcorper an mea, autem idque pri in. Duo homero delenit no, aperiri aliquando ei vel, scripta interesset usu ut. Iriure aliquip vivendum an sit, mea molestie consulatu democritum ne, in vix virtute vivendo petentium. Vix an habeo partem ullamcorper, in mei dissentiunt concludaturque. Ipsum accusata incorrupte vix an, an sed ferri tritani voluptatibus.

Putent nostrud in ius, dicta consectetuer has ex. Ad tota graeco comprehensam pri, usu reque nobis aliquando ut. Eam ut viderer quaestio accusamus, audire menandri conclusionemque ex vim. Ius ex solet fuisset, ei dicta iudico mel. No eum vivendo volutpat expetenda, menandri iracundia ea vim.

Fugit detracto liberavisse vel an, has an amet accusam. Mei facer intellegam te, nec forensibus adipiscing ex. Iusto aperiri an his. Ei cum bonorum dolorum, enim atqui ex cum.

Invenire interpretaris ei pri, omnes tantas vidisse at ius, essent vidisse et mel. Illud partiendo referrentur cu has, aliquip impedit vim no. Ex mel veritus antiopam. Habeo utinam quidam per ne. Dolorem ancillae vim ex, te quidam ornatus propriae duo. Dictas eripuit ex eam, ut reque choro maluisset usu.

An debet inermis eam. Mei dicit munere ex. Posse disputando et per. In mundi iuvaret evertitur nec, cu simul impedit volumus mel. His meis vidisse adolescens at.

Cibo placerat maiestatis ne est, vix ad mollis civibus dolores, nemore nostro sed no. No decore tempor persecuti eum, eirmod inermis laboramus no mei. Ei suas euripidis honestatis vis. Impedit singulis corrumpit nec ex. At duo sint delicata, ea justo dolor per.
    
    Lorem ipsum dolor sit amet, te eos facilis noluisse consetetur. Ei quodsi labitur vulputate vix. Vix no nisl ornatus, discere consequat te mea. Cu ius quem ferri assueverit, cu sit nulla persequeris concludaturque. Vim ut sale causae referrentur.

Id habemus pertinacia ius, mea fastidii convenire at. At sit postulant repudiandae, has ut natum delicatissimi. Quo liber veritus ponderum ea, his cu corrumpit consequuntur. Et cum apeirian percipitur, invidunt salutatus ex ius. Mea exerci conceptam ad, at vim accusata adipiscing.

Nam decore docendi cu, vide liber accusam eam ei, at quando malorum sapientem vis. Eam te hinc facer. Eu usu option intellegat, cibo debitis graecis sed ei, consul tempor id pri. Quo at dicam electram, qui ut nonumy nonumes constituam. Eos nibh quaestio efficiendi an, munere argumentum ei vix, ex cum nisl novum gubergren. Vix in veniam propriae, labitur sadipscing eu mel.

Qui ut ubique placerat euripidis. His esse eius ne, ut docendi gloriatur posidonium quo. Et inermis ceteros ius, ea pro novum ignota vivendo. Cum id vide laudem, augue inermis definitiones mea at, phaedrum dissentiunt te per.

Conceptam ullamcorper an mea, autem idque pri in. Duo homero delenit no, aperiri aliquando ei vel, scripta interesset usu ut. Iriure aliquip vivendum an sit, mea molestie consulatu democritum ne, in vix virtute vivendo petentium. Vix an habeo partem ullamcorper, in mei dissentiunt concludaturque. Ipsum accusata incorrupte vix an, an sed ferri tritani voluptatibus.

Putent nostrud in ius, dicta consectetuer has ex. Ad tota graeco comprehensam pri, usu reque nobis aliquando ut. Eam ut viderer quaestio accusamus, audire menandri conclusionemque ex vim. Ius ex solet fuisset, ei dicta iudico mel. No eum vivendo volutpat expetenda, menandri iracundia ea vim.

Fugit detracto liberavisse vel an, has an amet accusam. Mei facer intellegam te, nec forensibus adipiscing ex. Iusto aperiri an his. Ei cum bonorum dolorum, enim atqui ex cum.

Invenire interpretaris ei pri, omnes tantas vidisse at ius, essent vidisse et mel. Illud partiendo referrentur cu has, aliquip impedit vim no. Ex mel veritus antiopam. Habeo utinam quidam per ne. Dolorem ancillae vim ex, te quidam ornatus propriae duo. Dictas eripuit ex eam, ut reque choro maluisset usu.

An debet inermis eam. Mei dicit munere ex. Posse disputando et per. In mundi iuvaret evertitur nec, cu simul impedit volumus mel. His meis vidisse adolescens at.

Cibo placerat maiestatis ne est, vix ad mollis civibus dolores, nemore nostro sed no. No decore tempor persecuti eum, eirmod inermis laboramus no mei. Ei suas euripidis honestatis vis. Impedit singulis corrumpit nec ex. At duo sint delicata, ea justo dolor per.
</div>

<script>
    addEventListener("load", () => smartScrollbar("#container"));
</script>
              
            
!

CSS

              
                body {
    display: flex;
    flex-direction: column;
    align-items: center;
    
    background-color: whitesmoke;
    
    font-family: Cambria;
}

#container {
    position: relative;
    
    box-sizing: border-box;
    
    width: 75vw;
    height: 27rem;
    
    max-height: 90vh;
    
    text-indent: 2rem;
    
    padding: 0.25rem;
    padding-right: 2rem;
    
    border: 2px solid black;
    
    overflow-y: hidden;
    
    white-space: pre-wrap;
}
              
            
!

JS

              
                var smartScrollbar = (function(){ 
    function smoothScroll(element, to, duration)
    {
        let ticks = Math.ceil(duration / 60), 
            top = element.scrollTop;
        
        to = Math.max(Math.min(top + to, element.scrollHeight), 0);
        
        let diff = to - top,
            delta = diff / ticks,
            tick;
        
        let fn = () => {
            if(--ticks)
                requestAnimationFrame(fn);
            
            top += delta;
            
            element.scrollTop = top;
            
            calculatePosition(element);            
        };
        
        fn();
    }
    
    function calculateHeight(element)
    {
        let scrollbar = element.scrollbar;
        
        let rect = offset(element), scr = scroll(element);

        let height = rect.height;

        let ratio = height / scr.height, scaledHeight = ratio * rect.height;

        scrollbar.style.height = `${scaledHeight}px`;

        calculatePosition(element, rect, scr);
    }

    function calculatePosition(element, rect, scr)
    {
        let scrollgutter = element.scrollgutter, scrollbar = element.scrollbar;
        
        rect = rect || offset(element);
        scr = scr || scroll(element);

        let scrollbarRect = offset(scrollbar), scrollbarHeight = scrollbarRect.height;

        let top = scr.top;

        let scrollHeight = scr.height, comp = computed(element);

        let internalHeight = rect.height - (parseInt(comp.borderTopWidth) + parseInt(comp.borderBottomWidth));

        let newTop = Math.max(Math.min(top / scrollHeight * internalHeight, internalHeight - scrollbarHeight), 0);

        scrollgutter.style.top = top + "px";
        scrollbar.style.top = newTop + "px";
    }
    
    function vanishScrollbar(scrollbar, delay)
    {
        return setTimeout(() => scrollbar.style.opacity = "0", delay);
    }

    return function(target, options)
    {
        options = options || {};
        
        target = E1(target);
        
        var scrollgutter = create("div", {
            className: "smart-scroll-gutter"            
        });
        
        var scrollbar = create("div", {
            className: "smart-scrollbar",
            
            onmousedown: function(e)
            {
                this.setAttribute("data-drag-offset", e.offsetY);
                this.dragging = true;
            }
        });
        
        let gstyle = scrollgutter.style;
        
        gstyle.width = options.width || "8px";
        gstyle.height = "100%";
        
        gstyle.position = "absolute";
        gstyle.right = "2px";
        gstyle.top = "0";
        
        gstyle.pointerEvents = "auto";
        gstyle.userSelect = "none";
        
        let style = scrollbar.style;
        style.position = "absolute";
        style.top = "0";
        
        style.width = "100%";
        style.backgroundColor = options.backgroundColor || "#A0A0A0";
        style.opacity = "0";
        
        style.transition = "opacity 0.5s"
        
        on(scrollgutter, "mouseenter", (e) => {
            // Don't show the scrollbar if the scrollHeight and offsetHeight are the same
            if(target.scrollHeight == target.offsetHeight)
                return;
            
            calculateHeight(target);
            calculatePosition(target);
            
            clearTimeout(target.scrollbarVanish);
            
            style.opacity = "1";
        });

        on(scrollgutter, "mouseleave", (e) => {
            if(!scrollbar.dragging)
                target.scrollbarVanish = vanishScrollbar(scrollbar, 1000);
        });

        on(target, "wheel", (e) => {
            let target = e.currentTarget;
            
            // Don't do any scrolling if the scrollHeight and offsetHeight are the same
            if(target.scrollHeight == target.offsetHeight)
                return;
            
            let scr = scroll(target);

            let scrollAmount = e.deltaY;
            
            calculateHeight(target);
            
            smoothScroll(target, scrollAmount, 500);
            
            calculatePosition(target);
            
            clearTimeout(target.scrollbarVanish);
            
            style.opacity = "1";
        }, {
            passive: true
        });
        
        on("mousemove", (e) => {            
            if(scrollbar.dragging)
            {
                let rect = offset(target), comp = computed(target);

                let scrollHeight = target.scrollHeight,
                    internalHeight = rect.height - (parseInt(comp.borderTopWidth) + parseInt(comp.borderBottomWidth)),
                    scrollAmount = Math.min(Math.max((e.clientY - rect.top) - parseInt(scrollbar.dataset.dragOffset), 0), scrollHeight);
                
                target.scrollTop = (scrollAmount / internalHeight) * scrollHeight;
                
                calculatePosition(target);
            }
        });
        
        on("mouseup", (e) => {
            if(scrollbar.dragging)
            {
                scrollbar.removeAttribute("data-drag-offset");
                scrollbar.dragging = false;
                
                if(e.target != scrollgutter && !scrollgutter.contains(e.target))
                    target.vanishScrollbar = vanishScrollbar(scrollbar, 1000)
            }
        });
        
        target.scrollgutter = scrollgutter;
        target.scrollbar = scrollbar;
        scrollgutter.appendChild(scrollbar);
        target.appendChild(scrollgutter);
        
        calculateHeight(target);
    }
})();
              
            
!
999px

Console