就職してもうすぐ3年になりますが、初めて病欠しました。17日の木曜日から熱と下痢でダウンしており、丸々二日パソコンさえ触らないという状況でした。
それはともかく、Bootstrapの公式サイトにもあるサイドバーのメニュー。
スクロールして一番上まで来たら追従するようになり、さらにヘッダーまでくるとその位置でストップするような動きになっています。そして、そのメニューはメインの内容に対応して現在の位置がどこか示してくれます。前者は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独自の名前っぽいので、一般的な呼び名というのがあるのかもしれません。
コメント