jQuery スクロールに追従するサイドバー

jQuery スクロールに追従するサイドバー

最近はあまり見なくなりましたが、スクロールに追従(スクロールしても固定)するサイドバーをjQueryで書く案件があったのでブログの記事にしておきます。

この記事で使うイベントやメソッドなど

.scrollTop();
.css('prop', 'value');
$(window).scroll(function() { Do Something });

ヘッダーとフッターがあり、メインのコンテンツとサイドバーがある簡単な2カラムレイアウトで考えます。(都合上サイドバーは.side-barの中に追従するコンテンツを入れるといった入れ子のマークアップをします。)

jq-fixed-img-02.png

このレイアウトで追従して欲しいサイドバーの追従範囲はコンテンツの高さです。スクロールしてヘッダーが見えなくなった場所でサイドバーをページ上部に固定します。追従を解除する場所はフッターがサイドバーの最下部に到達した場所です。

まずは各要素の高さをそれぞれ変数に入れましょう。追従する範囲となるサイドバーの高さをコンテンツの高さと揃えます。合わせて追従を解除する場所(ヘッダーの高さとコンテンツの高さを足した値から追従するサイドバーの高さを引いた値)も変数に入れます。

jQuery Code

$(function() {
    //各要素の高さ
    var headerHeight = $('.page-header').height();
    var contentsHeight = $('.page-body').height();
    var fixedSideBarHeight = $('#fixed-side-bar').height();
    //サイドバーの高さをコンテンツの高さと揃える
    $('.side-bar').css('height', contentsHeight);
    //追従を解除する場所
    var scrollStopPos = headerHeight+contentsHeight-fixedSideBarHeight;
});

スクロールイベントが始まると、どれだけスクロールしたかを監視します。どれだけスクロールしたかのスクロール量はjQueryのメソッドである.scrollTop()で求めることができます。
追従を開始する場所と解除する場所に来たらそれぞれjQueryでCSSのプロパティを変更します。

jQuery Code

$(function() {
    //各要素の高さ
    var headerHeight = $('.page-header').height();
    var contentsHeight = $('.page-body').height();
    var fixedSideBarHeight = $('#fixed-side-bar').height();
    //サイドバーの高さをコンテンツの高さと揃える
    $('.side-bar').css('height', contentsHeight);
    //追従を解除する場所
    var scrollStopPos = headerHeight+contentsHeight-fixedSideBarHeight;
    //イベント開始
    $(window).scroll(function() {
        //スクロール量
        var scrollVal = $(window).scrollTop();
    });
}); 

ここからはif〜else if〜else文で条件を指定していきます。
if 追従区間 { 追従 } else if 追従解除位置 { 追従解除 } else { 通常 } と言う条件になります。

追従区間はスクロール量 > ヘッダーの高さ かつ 追従解除する場所 > スクロール量になります。 この条件になったら.css()position: fixed; top: 0;にします。

追従解除位置はスクロール量 > 追従解除する場所になります。
この条件になったらposition: absolute; bottom: 0にします。

通常(追従範囲外)の場合はposition: static;とします。

jQuery Code

$(function() {
    //各要素の高さ
    var headerHeight = $('.page-header').height();
    var contentsHeight = $('.page-body').height();
    var fixedSideBarHeight = $('#fixed-side-bar').height();
    //サイドバーの高さをコンテンツの高さと揃える
    $('.side-bar').css('height', contentsHeight);
    //追従を解除する場所
    var scrollStopPos = headerHeight+contentsHeight-fixedSideBarHeight;
    //イベント開始
    $(window).scroll(function() {
        //スクロール量
        var scrollVal = $(window).scrollTop();
        //追従区間
        if(headerHeight < scrollVal && scrollStopPos > scrollVal) {
            $('#fixed-side-bar').css({
                'position': 'fixed',
                'top': '0'
            });
        //追従解除
        } else if(scrollStopPos < scrollVal) {
            $('#fixed-side-bar').css({
                'position': 'absolute',
                'top': '',
                'bottom': '0'
            });
        //デフォルト
        } else {
            $('#fixed-side-bar').css('position', 'static');
        }
    });
});

View Demo