Bootstrap 2.1 から追加されたJavaScriptプラグイン「Affix」とは、
Bootstrapのサイトでも実装されている。
以下の赤で囲った部分がAffixになっている。
Affix要素の位置まで通常スクロール。それを越えるとAffix要素が追従する。そして下の要素(フッター)の前で止まる。
まずはドキュメントを読んで実装
ドキュメント: Bootstrap > JavaScript > Affix
1. Affixプラグインを読み込んで「data-spy=”affix”」を記述
<div data-spy="affix">...</div>
→ 動作サンプル1
・下の要素を突き抜けてしまう
2. data-offset-top を指定
<div data-spy="affix" data-offset-top="200">...</div>
→ 動作サンプル2
・追従を開始すると余白が発生する(上の要素の高さ分の余白)
・下の要素を突き抜けてしまう
というように、なかなかうまくいかない。
結局、マークアップだけではなく、CSSとaffixメソッドで制御しなければならないっぽい。
CSSとaffixメソッドで実装
まずは成功っぽい例から
→ 動作サンプル3
<div class="my_affix"> ... </div>
$('.my_affix').affix({ offset: { top: 200, bottom: 220 } });
・offset:bottom は、下の要素の高さ(フッタ(=200)+余白(=20))を指定
・.affix は「position: fixd」になるので、「top: 0」を指定して、上の要素の高さを相殺しないようにする
・.affix-bottom は「position: absolute」で、「bottom: 220px(=offset: bottom)を指定する。
仕組みは以下
Affixプラグインの仕組みを図解
まず、Affix要素はスクロール量とoffset引数によって、「.affix-top → .affix → .affix-bottom」と、クラスが自動的に変化していく。
offset引数(offset:top, offset:bottom)は以下の高さを指定する。
そうすると、状態変化と共にクラスが変化していく。
という仕組みがわかれば、さきほどの動作サンプル3でいいように見える。
でもこれは不完全。
正確には、”BootstrapのCSSを読みこんでいる場合”は不完全。
Bootstrapのサイトで実装されているAffixへの疑問
BootstrapのCSSを読み込んでいる場合、これだけではうまくいかないはず。
Affixが発動すると親要素の高さがゼロになるはず
追従を開始する(.affix)と、通常フローから逸脱する、つまり「position: fixed」になるで、Affix要素と並列の要素がないと親要素の高さがゼロになってしまう。
よって、親要素がグリッドレイアウトだった場合、並列のグリッドレイアウトが左寄せになってしまうはず。
少なくとも、Bootstrap2.1ではそうなるはず。
だが、現在のBootstrapのサイトではちゃんと動いているように見える。
なんでだろう?と思ったら、姑息なことをしていた…
[class*="span"] { ... min-height: 1px; }
「min-height: 1px;」とはなかなかスマートではない…
それよりもなによりも、ドキュメントには記載されていないカスタムCSSを書いてるのか!?という疑惑。
Bootstrap2.1.1のCSSには「min-height: 1px」が確かに記述されている。Bootstrap2.1.0にはない。
なるほど。どうやら、しれっとバグフィックスした模様。
スマートな方法ではないが、とりあえずはこれはOK。
グリッドレイアウトの可変幅にはフィットしないはず
Affix要素は「position: fixed」になるので、親要素が可変グリッドだったとしても、その幅にはフィットしない。
Bootstrapのサイトではどうなっているかというと、結局、親要素にクラスを振って、幅をpx固定している。
さらに、Bootstrapはレスポンシブデザインで設計されているので、画面サイズによってAffix要素の横幅も流動的に変化していくので、Affix要素もメディアクエリごとに細かく指定している模様。
レスポンシブを前提に実装するなら仕方ないが、Affixプラグインだけを使いたい場合はけっこうな手間。
ということで、BootstrapのレスポンシブCSSは使わず、あくまでもAffixプラグインだけ使うパターン↓
BootstrapのCSSを読み込まず、Affixプラグインだけを使うパターン
→ 動作サンプル4
<!DOCTYPE HTML> <html lang="ja"> <head> <meta charset="UTF-8"> <title>Bootstrap Affix</title> <style type="text/css"> body { position: relative; margin: 0; } .header, .footer { height: 200px; background: #e3e3e3; } .container { width: 960px; margin: 0 auto; } .left_column { float: left; } .right_column { padding: 20px 0 20px 220px; } .content { background: #eee; } .my_affix { margin: 20px 0 0; width: 200px; background: #eee; float: left; } .my_affix.affix { position: fixed; top: 0; } .my_affix.affix-bottom { position: absolute; top: auto; bottom: 220px; } </style> </head> <body> <header class="header"> </header> <div class="container"> <div class="left_column"> <div class="my_affix"> ... </div> </div> <div class="right_column"> <div class="content"> ... </div> </div> </div> <footer class="footer"> </footer> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script> <script src="./js/bootstrap.js"></script> <script type="text/javascript"> $(function(){ $('.my_affix').affix({ offset: { top: 200, bottom: 220 } }); }); </script> </body> </html>
まとめ
・offset引数は必ず指定した方がいい。
・スクロール量とoffset引数によって、「.affix-top → .affix → .affix-bottom」とクラスが自動的に変化していく。
・クラス変化=状態変化に応じて、CSSで制御する必要がある。
個人的は意見としては、レスポンシブデザインをベースに開発されているBootstrapのJavaScriptプラグインなのに、レスポンシブに完全に対応できていないAffixプラグインはどうなの?という感じはちょっとありますね。
Comments
[…] Bootstrap 2.1「Affixプラグイン」がわかりにくかったので少し紐解いてみました | hijiriworld Web […]