Bootstrap3のAffixとScrollspyを試してみた

就職してもうすぐ3年になりますが、初めて病欠しました。17日の木曜日から熱と下痢でダウンしており、丸々二日パソコンさえ触らないという状況でした。

それはともかく、Bootstrapの公式サイトにもあるサイドバーのメニュー。
affix

スクロールして一番上まで来たら追従するようになり、さらにヘッダーまでくるとその位置でストップするような動きになっています。そして、そのメニューはメインの内容に対応して現在の位置がどこか示してくれます。前者はAffix、後者はScrollSpyという方法を使うと実装できるようです。

というわけで作ってみたのそのメモ。

HTML

<div class="container">
    <header>HEADER</header>
    <div class="row">
        <div class="col-sm-3">
            <nav class="affix-nav">
                <ul class="nav">
                    <li><a href="#article1">1番目</a></li>
                    <li><a href="#article2">2番目</a></li>
                    <li><a href="#article3">3番目</a></li>
                    <li><a href="#article4">4番目</a></li>
                    <li><a href="#article5">5番目</a></li>
                </ul>
            </nav>
        </div>
        <div class="col-sm-9" id="main">
            <article id="article1">
                <h1>1番目</h1>
            </article>
            <article id="article2">
                <h1>2番目</h1>
            </article>
            <article id="article3">
                <h1>3番目</h1>
            </article>
            <article id="article4">
                <h1>4番目</h1>
            </article>
            <article id="article5">
                <h1>5番目</h1>
            </article>
        </div>
    </div>
    <footer>FOOTOR</footer>
</div>

CSS

header,footer{
    height:300px;
    text-align:center;
    font-size:50px;
    line-height:300px;
    background-color:#eee;
}
#main article{
    height:300px;
    border:1px solid black;
    margin:20px 0;
}
.affix-nav{
    width:263px;
}
.affix-nav.affix{
    top:0;
    position:fixed;
}
.affix-nav.affix-top{
    position:static;
}
.affix-nav.affix-bottom{
    position:absolute;
}
.affix-nav .nav li{
    background-color:#8f8;
    border-left:1px solid black;
    border-right:1px solid black;
    border-bottom:1px solid black;
}
.affix-nav .nav li:first-child{
    border-top:1px solid black;
}
.affix-nav .nav li.active{
    background-color:#4c4;
}

JavaScript

$(function(){

    $('nav.affix-nav').affix({
        offset:{
            top: 300,
            bottom:300
        }
    }).on('affix.bs.affix', function () {
        $(this).css({
                'top': '0'
        });
        console.log('affix.bs.affix');
    }).on('affixed.bs.affix', function(){
        console.log('affixed.bs.affix');
    }).on('affix-bottom.bs.affix', function(){
        console.log('affix-bottom.bs.affix');
    }).on('affixed-bottom.bs.affix', function(){
        console.log('affixed-bottom.bs.affix');
    });

    $('body').scrollspy({ target: 'nav.affix-nav' })
});

3~19行目がAffixの記述(といっても、console.logをやっているだけのところは必要ないですが)、21行目がScrollSpyの記述です。

実行サンプル:Bootstrap3のAffixとScrollspyを試してみた
ブラウザの高さを狭くして、一番下までスクロールしたらフッターの上でメニューの位置がストップするのがわかると思います(とはいっても、Chromeでしか動作確認してないのですが・・・)。

以下、作成する際に手こずったこと。

はじめ、スクロールを一番下までやった後にスクロールを上に戻すと、なぜかフッターの直前でメニューがストップしたままになってしまっていました(一番上までやるともとに戻る)。とりあえず、Affixにはいろいろイベントが用意されているようなので、affix.bs.affix(affixが発生する直前に発生)、affixed.bs.affix(affixが発生した直後に発生)、affix-bottom.bs.affix(affixが最下部に到達した時に発生)、affixed-bottom.bs.affix(affixが最下部に到達した直後に発生)というイベントを呼ぶとそれぞれのイベント名をコンソールに吐き出すようにしてみることに。すると、一番下までスクロールした時に『affix-bottom.bs.affix』『affixed-bottom.bs.affix』という順番に呼ばれた後、もう一度上にスクロールすると『affix.bs.affix』『affixed.bs.affix』が呼ばれるのだけれども、またそのすぐ後に『affix-bottom.bs.affix』『affixed-bottom.bs.affix』が呼ばれているのを確認。この中間の『affix.bs.affix』『affixed.bs.affix』が呼ばれた時点でのメニューの属性を確認してみるとstyleのtopがaffix-bottomの時のままになっていました。いろいろ調べて原因が分からなかったのでとりあえず『affix.bs.affix』が呼ばれた時点でtopを0にするようにしています(上記JavaScriptのコードの10行目)。でも、こんなことやってるところなさそうなので、やっぱり自分の何かが間違っているのだと思います。

ちなみに、『affix.bs.affix』とかのイベントは古いBootstrap3のバージョンでは動いてくれませんでした。今回のサンプルは現在最新のバージョン3.1.1で試しています。後、CSSの指定も意外と重要っぽいです。クラスがaffix-topの時の指定、クラスがaffixの時の指定、クラスがaffix-bottomの時の指定はちゃんと書いたほうがよさそうでした(上記CSSのコードの16行目から25行目)。

ScrollSpyのほうは、たいして手こずることはなかったのですが、1つ手こずったのがメニューのクラスに”nav”をつけなければいけないということに最初気づかず、迷いました。なんでnavクラスだけにしてるんだろう・・・。

余談ですが、Affixの機能は一般的にスティッキーサイドバーと呼ばれています。予想できるかもしれませんが、メニューではなくヘッダー追従型だと、スティッキーヘッダーという名前になります。ScrollSpyもBootstrap独自の名前っぽいので、一般的な呼び名というのがあるのかもしれません。

コメント

タイトルとURLをコピーしました