追従するサイドバー

追従範囲を指定したサイドバーです。
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にして下揃えにします。

デモページ