[jQuery] 特定の要素内だけスクロールに追随するサイドバーを作る方法

画面をスクロールしてもついてくるサイドバーのレイアウトをよく見かけます。応用として、特定要素の中だけサイドバーを追随させたいという場合もあるかと思います。海外のサイトですが、そのパターンのチュートリアルが公開されていたので参考にさせて頂きサンプル(IE7まで動作確認済みです)を作ってみました。作成の手順とコードのメモなどです。

作ったサンプルデモ

main要素内だけ追随するのがわかりやすいようヘッダーとフッターがやたら大きいです。
#main要素内だけ追随するサイドボックスのデモ|memocarilog

作成の手順

HTML

このサンプルでは#main要素内でのみ可動するようにする為、#main要素内に可動部分の#side要素を置きます。

<div id="main">
	<div id="side">サイドバー部分</div>
</div>

CSS

CSSはまず #mainに対して position: relative を設定します。次に#sideに対して position: absolute を設定して位置を指定します。

  #main{
    position: relative;
  }
  #side{
    position: absolute;
    top: 20px;
    left: 20px;
    width: 200px;
    height: 200px;
  }

jQuery

元記事のコードより追随できる範囲の計算部分のコードを参考にさせて頂きましたが、よりシンプルになるように端折った為だいぶ短いコードになっています。

ヘッド内でjQuery本体を読み込みます。

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>

続けて以下のように記入します。作ったサンプルのコードはこのページの下にまとめてあります。

下のコメント内にもありますが、min_move と max_move にて追随できる範囲を決めて、その中のみ margin-top の値を変えて追随させています。それ以外の領域になったときには main要素の上か下にくっつくような margin-top 値を与えます。

<script>
$(function(){

	var side = $("#side");
	// #sideのオブジェクトをsideへ
	var main = $("#main");
	// #mainのオブジェクトをmainへ
	var min_move = main.offset().top;
	// #side が動ける最初の地点(main要素のtopの位置)
	var max_move = main.offset().top + main.height() - side.height() - 2*parseInt(side.css("top") );
	// max_move は トップから #side が動ける最終地点までの長さ → #main 要素の内側の高さ内
	// max_move ←( #mainボックスのトップの位置の値 + #mainボックスの高さ ー #sideの高さ ー サイドのトップ値✕2)
	var margin_bottom = max_move - min_move	;
	// side要素の一番下にいる時のmargin-top値の計算
	
	// スクロールした時に以下の処理		
	$(window).bind("scroll", function() {
			
		var wst =  $(window).scrollTop();
		// スクロール値が wst に入る
			
		// スクロール値が main 要素の高さ内にいる時以下
		if( wst > min_move && wst < max_move ){
			var margin_top = wst - min_move ;
			// スクロールした値から min_move(#mainのtopの表示位置)を引いたのを margin_top へ
			side.animate({"margin-top": margin_top},{duration:600,queue:false});
			// サイド CSSの margin-top の値を、変数の margin_top にする
				
		// スクロールした値が min_move(main要素の高さより小さい)以下の場合はCSSのマージントップ値を0にする
		}else if( wst < min_move ){
			side.animate({"margin-top":0},{duration:600,queue:false});
		
		// スクロールした値が max_move (main要素の高さより大きい)以上の場合以下
		}else if( wst > max_move ){
			side.animate({"margin-top":margin_bottom},{duration:600,queue:false});
		}
	});	
});
</script>

これで、指定要素の中だけスクロールに応じてサイドがついてくるようになります。

メモ:scrollTop() の挙動について

以前にエントリーした記事の(スクロールしてもついてくるサイドメニューをjQueryとcssで作るチュートリアル)、追随するサイドバーのコードはオブジェクトを $(document).scrollTop() にしていましたが、$(document) ではブラウザによっては正しく座標を取れないため、$(window)にしたほうがよいようです。

作ったサンプルのコード

HTML-head内

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
<script>
$(function(){
	var side = $("#side");
	var main = $("#main");
	var min_move = main.offset().top;
	var max_move = main.offset().top + main.height() - side.height() - 2*parseInt(side.css("top") );
	var margin_bottom = max_move - min_move	;

	$(window).bind("scroll", function() {
		var wst =  $(window).scrollTop();
		if( wst > min_move && wst < max_move ){
			var margin_top = wst - min_move ;
			side.animate({"margin-top": margin_top},{duration:600,queue:false});
		}else if( wst < min_move ){
			side.animate({"margin-top":0},{duration:600,queue:false});
		}else if( wst > max_move ){
			side.animate({"margin-top":margin_bottom},{duration:600,queue:false});
		}
	});	
});
</script>

HTML-body内

<body>
<div id="header">
	<p>#main要素内だけ追随するサイドボックスのデモ|memocarilog</p>
</div>
<div id="main">
	<div id="side">
		<p>#side</p>
	</div>
		
	<p>↑</p>
	<p>↑</p>
	<p>#main</p>
	<p>↓</p>
	<p>↓</p>
</div>

<div id="footer">
	<p>&lt;!-- footer --&gt;</p>
	<p class="back"><a href="#">▲元のページへ戻る</a></p>
</div>
</body>

CSS

ody{ 
    margin:0 auto;
    padding:0;
    width:960px;
    border:0;
    text-align:center;
    font-size:30px;
    font-family:arial;
  }
  #header{
    height:350px;
    background:#eee;
  }
  #header h1{
	padding: 130px 50px 0;
	font-weight: normal;
	
  }
  #footer{
    height:700px;
    background:#eee;
  }
  #footer .back{
	font-size: 16px;
  }
  #main{
    position: relative;
    min-height: 500px;
    border: dotted 5px #faa;
    background:#F6E4ED;
  }
  #side{
    position: absolute;
    top: 20px;
    left: 20px;
    width: 200px;
    height: 200px;
    background: #F14052 ;
  }
  p{
	padding: 50px 20px;
  }

Related Article

No Comments & Tracbacks

Leave a Comment

Emailは公開されません。*は必須項目です。


*


Categorys

Tags

CSS3 ダッシュボード ヘッダー トラブル コードサンプル コンテンツ スライドショー jQueryプラグイン php 引っ越し 素材 お知らせ JavaScript Facebook CSS カテゴリー 投稿タイプ IE HTML5 Shareボタン seo レスポンシブ Photoshop タクソノミー ナビゲーション カスタムメニュー Git Macアプリ サイドバー WPセキュリティ SVG iTunes PHPリファレンス API WP使い方 query_posts データベース get_posts() 条件分岐 コメント function RSS スマートフォン Sass/Compass さくらVPS