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 […]