Sticky Sidebar

by Petr Haluza

HTML

<div id="wrap">

    <header id="header" role="banner">Header</header>
    
    <main id="content" role="main">
        <div id="main-column">Main</div>
        <aside id="sidebar" role="complementary">Sidebar</aside>
        
    </main>
    
    <footer id="footer" role="contentinfo">Footer</footer>
    
</div>

CSS

body {
    color: #333;
    font-family: Arial, Helvetica, sans-serif;
}

main {
    display: block;
}

#wrap {
    width: 500px;
    margin: 20px auto;
}

#header, #footer {
    background: #ddd;
    padding: 15px;
    border-radius: 5px
}

#header {
    margin-bottom: 5px;
    height: 100px;
}

#content {
    background: #ddd;
    margin-bottom: 5px;
    padding: 5px;
    position: relative;
    border-radius: 5px;
}

#sidebar, #main-column {
    background: #fff;
    border: 1px solid #ccc;
    padding: 15px;
}

#sidebar {
    position: absolute;
    width: 169px;
    height: 200px;
}

#sidebar.fixed {
    position: fixed;
    top: 0;
}

#sidebar.bottom {
    bottom: 5px;
}

#main-column {
    margin-left: 205px;
    width: 253px;
    height: 2000px;
    min-height: 400px;
}

#footer {
    height: 500px;
}

JavaScript

/*!
 * StickySidebar jQuery Plugin v1.0.1
 * Copyright 2014 Dawid Pawelec
 * Released under the MIT license
 */

(function ($) {
    var $w = $(window);

    $.fn.stickySidebar = function (options) {
        var o = $.extend({}, $.fn.stickySidebar.defaults, options),
            $c = $(o.container);

        return this.each(function () {
            var $s = $(this),
                sh = $s.outerHeight(),
                originalMarginTop = parseInt($s.css('margin-top'), 10),
                top = $s.offset().top - o.offsetTop - originalMarginTop,
                bottom = $c.offset().top + $c.outerHeight() - o.offsetTop,

                handleScroll = function () {
                    var scroll = $w.scrollTop();
                    if (scroll > top) {
                        if (scroll + sh + o.offsetBottom > bottom && o.bottom) {
                            $s.removeClass(o.stuckClass);
                            $s.addClass(o.bottomClass);
                        } else {
                            $s.css('margin-top', o.offsetTop + originalMarginTop);
                            $s.addClass(o.stuckClass);
                        }
                    } else {
                        $s.css('margin-top', originalMarginTop);
                        $s.removeClass(o.stuckClass);
                        $s.removeClass(o.bottomClass);
                    }
                };

            $w.on('scroll', handleScroll);
        });

    };

    $.fn.stickySidebar.defaults = {
        stuckClass: 'fixed',
        bottomClass: 'bottom',
        container: '#content',
        offsetTop: 0,
        offsetBottom: 0,
        bottom: true
    };

}(jQuery));



// Usage
$('#sidebar').stickySidebar({
    container: '#content',
    offsetBottom: 5
});