追従するサイドバー

追従範囲を指定したサイドバーです。
resizeした時にも対応させていますので、サイドバーが突き抜けることはありません。
デモではわかりやすく各要素にheightを指定しています。

追従している時は.sideにfixedというクラスを、追従をやめたら.sideにstopというクラスが付きますのでstyle変更も容易です。

デモページ

HTML

        <header class="header">
            <div class="headerInner">
                <h1>header</h1>
                <p>height:200px</p>
            </div>
        </header>
            <div class="container">
                <main class="main">
                    <div class="box">
                        height:1500px
                    </div>
                </main>
                <div class="side">
                    <div class="sideInner">
                        <ul>
                            <li>メニュー
                                <ul>
                                    <li>小メニュー</li>
                                    <li>小メニュー</li>
                                    <li>小メニュー</li>
                                    <li>小メニュー</li>
                                </ul>
                            </li>
                            <li>メニュー
                                <ul>
                                    <li>小メニュー</li>
                                    <li>小メニュー</li>
                                    <li>小メニュー</li>
                                    <li>小メニュー</li>
                                </ul>
                            </li>
                            <li>メニュー
                                <ul>
                                    <li>小メニュー</li>
                                    <li>小メニュー</li>
                                    <li>小メニュー</li>
                                    <li>小メニュー<br><br>height:600px</li>
                                </ul>
                            </li>
                        </ul>
                    </div>
                </div>
            </div>
        <footer class="footer">
            <div class="footerInner">
                <h2>footer</h2>
                <p>height:300px</p>
            </div>
        </footer>

CSS

    body{
        margin:0;
        padding:0;
    }
    h1,h2{
        margin:0;
        padding:0;
    }
    ul{
        margin:0;
    }
        .header{
            width: 100%;
            height: 200px;
            background: rgb(137, 249, 114);
        }
        .headerInner{
            width: 100%;
            max-width: 1000px;
            margin:0 auto;
            padding:10px 0;
            box-sizing: border-box;
        }
        .container{
            width: 100%;
            max-width: 1000px;
            margin:0 auto;
            display: table;
        }
        .main{
            display: table-cell;
            height: 1500px;
            padding: 30px 0;
            vertical-align: top;
            box-sizing: border-box;

        }

        .footer{
            width: 100%;
            height: 300px;
            background: rgb(137, 249, 114);
        }
        .footerInner{
            width: 100%;
            max-width: 1000px;
            margin:0 auto;
            padding:10px 0;
            box-sizing: border-box;
        }

        /*=====================
        side
        =====================*/
        .side{
            display: table-cell;
            width: 300px;
            padding: 30px 0;
            vertical-align: top;
            box-sizing: border-box;
        }

        .sideWrap{
            position: relative;
            width: 300px;
            height: 100%;
            padding:0;
        }

        .sideInner{
            width: 330px;
            height: 600px;
            background:#ddd;
            margin: 0 auto;
            box-sizing: border-box;
        }
        .sideInner.fixed{
            position: fixed;
            top: 30px;
        }
        .side{
            display: table-cell;
            width: 330px;
            max-width: 330px;
            box-sizing: border-box;
            vertical-align: top;
            background: #808080;
        }

javascript(jQuery)

function sideFixed(){

        var sideInner = jQuery('.sideInner');
        var side =jQuery('.side');

        // sideのtop位置を取得
        var sideOffsetTop =side.offset().top;

        //sideの高さ
        var sideHeight =jQuery('.side').outerHeight();

        //sideInnerの高さ
        var sideInnerHeight =jQuery('.sideInner').outerHeight();


        //sideの下計算
        //sideの高さ + sideのtop開始位置 - ( sideInnerの高さ +[ sideのpadding-bottom:30px +  .sideInner.fixedのtop:30px分 ] )
        //1500 + 200 - ( 600 + 60 ) = 1140
        //1140pxスクロールしたら追従をやめる
        var sideBottom =sideHeight+sideOffsetTop-(sideInnerHeight+60);

        jQuery(function(){
            function scrollPc() {
                var topScroll =jQuery(window).scrollTop();

                if(topScroll>sideOffsetTop && topScroll<sideBottom){
                    //スクロール値がsideのtop位置よりも大きい時かつ、
                    //スクロール値が1140pxよりも小さい時

                    // fixed
                    sideInner.addClass('fixed');
                    sideInner.removeClass('stop');
                    side.css('vertical-align','top');

                }else if(topScroll>sideOffsetTop && topScroll>=sideBottom){
                    //スクロール値がsideのtop位置よりも大きい時かつ、
                    //スクロール値が1140pxと等しい、または大きい時

                    //stop
                    sideInner.removeClass('fixed');
                    sideInner.addClass('stop');
                    //table-cellなのでvertical-alignを使えます
                    side.css('vertical-align','bottom');

                }else{
                    //上記に当てはまらないもの
                    //(スクロール値がsideのtop位置よりも小さい時)

                    // top
                    sideInner.removeClass('fixed');
                    sideInner.removeClass('stop');
                    side.css('vertical-align','top');
                }
                return false;
            }
            scrollPc();
            //スクロールした時に実行
            jQuery(window).scroll(function(){
                scrollPc();
            });
        });
    }
    //loadとresizeした時に実行
    jQuery(function(){
        jQuery(window).on('load resize',function(){
            sideFixed();
        });
    });

スクロールの値に応じて3段階に分ける

最初~header通過まで

最初は追従せずに、そのまま表示。

header通過~footer上30pxまで

headerを過ぎたらposition:fixedで追従させる。
side.offset().top;でsideのtop位置を取得できます。
この領域に来たら.sideInnerにfixedのclassを付けます。

footer上30pxから~最後

このままfixedだと突き抜けてしまうので、footer上30pxまで来たら追従をストップしたい。
ブラウザの一番上から、footer上30pxまでの高さが分かればいい。
今回はsideの高さ + sideのtop開始位置 – ( sideInnerの高さ + sideのpadding-bottom:30px + .sideInner.fixedのtop:30px分 )で計算しました。
sideのpadding-bottom:30pxと、追従しているときに.sideInnerのtopを30px開けていますので、2つ合わせて60pxです。

cssで.containerはdisplay:tableに、.mainと.sideはdisplay:table-cellにしてあるので、高さを求めるのが容易です。
この領域に来たらs.ideInnerにstopのclassを付けます。
また.sideはdisplay:table-cellのため、vertical-alignを使えますのでbottomにして下揃えにします。

デモページ

  • コーダーのための計算機