HTML5
CSS3
jQuery

スクロールするとナビゲーション固定(フッターまでスクロールすると消えるタイプ・開閉式のコンテンツ含む)

ナビゲーションを固定するtipsはよく見かけますが、
開閉するコンテンツが含まれる場合、documentの高さをどうやって再取得したら良いんだろう、、、
と少しハマってしまったので、メモメモ。

sample.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>header固定+ドロップダウン</title>
    <link href="sample.css" rel="stylesheet">
</head>

<body>
    <header><h1>header固定+ドロップダウンのサンプル</h1></header>

   <nav>
       <ul>
           <li>リスト1</li>
           <li>リスト2</li>
           <li>リスト3</li>
           <li>リスト4</li>
       </ul>
   </nav>

    <main>
        <section>
            <h2>ココをクリックすると内容が開きます。</h2>
            <p>これが内容です。これが内容です。これが内容です。これが内容です。これが内容です。これが内容です。これが内容です。これが内容です。これが内容です。これが内容です。これが内容です。これが内容です。</p>
        </section>

        <section>
            <h2>ココをクリックすると内容が開きます。</h2>
            <p>これが内容です。これが内容です。これが内容です。これが内容です。これが内容です。これが内容です。これが内容です。これが内容です。これが内容です。これが内容です。これが内容です。これが内容です。</p>
        </section>

        <section>
            <h2>ココをクリックすると内容が開きます。</h2>
            <p>これが内容です。これが内容です。これが内容です。これが内容です。これが内容です。これが内容です。これが内容です。これが内容です。これが内容です。これが内容です。これが内容です。これが内容です。</p>
        </section>

        <section>
            <h2>ココをクリックすると内容が開きます。</h2>
            <p>これが内容です。これが内容です。これが内容です。これが内容です。これが内容です。これが内容です。これが内容です。これが内容です。これが内容です。これが内容です。これが内容です。これが内容です。</p>
        </section>

        <section>
            <h2>ココをクリックすると内容が開きます。</h2>
            <p>これが内容です。これが内容です。これが内容です。これが内容です。これが内容です。これが内容です。これが内容です。これが内容です。これが内容です。これが内容です。これが内容です。これが内容です。</p>
        </section>
    </main>

    <footer></footer>
</body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="sample.js"></script>
</html>
sample.css
@charset "UTF-8" ;

*{
    margin: 0;
    padding: 0;
    box-sizing: border-box;
    text-align: center;
}

header{
    height: 200px;
    background: #baa7c5;
    color: #fff;
}
header h1{
    line-height: 6;
}

nav{
    background: #2e889c;
    transition: .3s;
}
nav ul{
    display: flex;
    list-style: none;
    justify-content: center;
}
nav ul li{
    padding: 10px 20px;
}

main{ padding-top: 50px;}
main section{
    max-width: 960px;
    margin: 0 auto 50px;
    background: #f0f0f0;
    padding: 20px;
}
main section h2{ margin-bottom: 10px;}
main section h2 + p{
    display: none;
    background: #888;
    color: #eee;
    margin-top: 10px;
    padding: 10px;
}

.is-fixed {
    position: fixed;
    bottom: 0;
    left: 0;
    z-index: 2;
    width: 100%;
}
.is-hide {
    transform: translateY(100%);
}

footer{
    height: 200px;
    background: #2c3e50;
    color: #fff;
}
sample.js
$(function() {

    //開閉
    $("h2").on("click", function() {
        $(this).next("p").slideToggle().toggleClass("open");
        if ($(this).next("p").hasClass("open")) {
            $(this).text("ココをクリックすると内容が閉じます。");
        }
        else {
            $(this).text("ココをクリックすると内容が開きます。");
        }
    });

    //nav固定
    var $win = $(window),
        $main = $('main'),
        $nav = $('nav'),
        navHeight = $nav.outerHeight(),
        footerHeight = $('footer').outerHeight(),
        docmentHeight = $(document).height(),
        navPos = $nav.offset().top,
        fixedClass = 'is-fixed',
        hideClass = 'is-hide';

    /* スクロールした時 */
    $win.on('load scroll', function() {
        var value = $(this).scrollTop(),
            scrollPos = $win.height() + value;

        if ( value > navPos ) {
            if ( docmentHeight - scrollPos <= footerHeight ) {
                $nav.addClass(hideClass);
            } else {
                $nav.removeClass(hideClass);
            }
            $nav.addClass(fixedClass);
        } else {
            $nav.removeClass(fixedClass);
        }
    });

    /* 開閉してdocumentの高さが変わった時 */
    $("h2").on('click', function(){
        $win.on('load scroll', function() {
            var value02 = $(this).scrollTop(),
                docmentHeight02 = $(document).height(),
                scrollPos02 = $win.height() + value02;

            $nav.removeClass('is-hide');
            if ( value02 > navPos ) {
                if ( docmentHeight02 - scrollPos02 <= footerHeight ) {
                    $nav.addClass(hideClass);
                } else {
                    $nav.removeClass(hideClass);
                }
                $nav.addClass(fixedClass);
            } else {
                $nav.removeClass(fixedClass);
            }
        });
    });

});

スクロールした時とクリックした時を一緒に処理しようとしていたために、
ややこしく感じてしまいました。
結果、分けて書けば特に難しいことはなかったです。
(もっとスマートな書き方があれば教えてください。)

参考

ナビゲーションの固定に関しては、こちらの記事の5番目を参考にしました。
大変わかりやすい記事でありがたいです。
jQuery:スクロールしたらヘッダーやナビゲーションを固定・変化させる動きを実装するサンプルコード 5/NxWorld