2012/03/30

Tag : ,

スクロールについてくる要素とその可動範囲の指定。あれ?この場合ついていかない要素ってことになるのかな?

長いページをスクロールしているとサイドメニューなどが見えなくなるときがありますよね。その場合、他のページに移動するにはヘッダーもしくはフッダー、サイドメニューの見える位置までスクロールしないといけません。結構、嫌になるときがありますよね。。。それを解消するには、ページのどの位置にいてもメニューが見えていればいいのです。簡単ですね。そう、お気づきのとおり「 position: fixed 」です。ただ、メニューの位置を初期位置のまま固定する仕様だとデザインの幅が狭くなりますので、指定した範囲を超えたら固定にするとかにしたほうがいいですね。

スクロールについてこなくなる(位置固定になる)要素を「div.menu」とすると。

html

<div id="main">
	<div id="column-left">
		<div class="menu">
			<ul>
				//省略
			</ul>
		</div>
		<div class="content">
			//省略
		</div>
	</div><!-- /#column-left -->
</div><!-- /#main -->

css

#column-left{
	position: relative;
	}
.menu{
	position: absolute;
	top:0;
	}

初期位置は親要素を基準とした(0,0)の位置に絶対位置指定。

jQuery

var memuPosi = $("div.menu").offset(); //要素(.menu)の初期位置情報です。
var menuTopMargin = 67; //fixed時のトップマージン値。
var targetScrollValue = memuPosi.top - menuTopMargin; //position切替の境となるスクロール値

$(window).scroll(function() {
	//var wScrollvalue = $('html,body').scrollTop();
	var wScrollvalue = $(window).scrollTop();
	if(wScrollvalue > targetScrollValue){
		$("div.menu").css({
			position: "fixed",
			top: menuTopMargin
			});
		}
	else{
		$("div.menu").css({
			position: "absolute",
			top: "0"
			});
		}
});
  • $(window).scrollTop();
    指定要素の現在のスクロールの上位置を返します。※ $(‘html,body’).scrollTop(); で動くはずだったのですが、なぜかsafariで値が返ってきませんでした。$(window).scrollTop(); だと大丈夫なようです。safari、Firefoxは動作確認済み。
  • if(wScrollvalue > targetScrollValue){
    スクロールの値が境を超えたかどうかで処理を切り替えます。

Sample

↓ 因に、初期位置から動かない頑固者指定はこちら。
Sample

あっ。可動範囲を指定したサンプル、忘れてました。では、気を取り直して。

指定範囲内だけ、ついてこなくなる要素。


可動範囲を親要素にし、スクロールについてこなくなるのは子要素にする。「箱入り娘」指定ですね。

html

<div id="main">
	<div id="column-left">
		<div class="menu-parent"> // 親
			<div class="menu"> // 子
				<ul>
					//省略
				</ul>
			</div>
		</div>
		<div class="content">
			//省略
		</div>
	</div><!-- /#column-left -->
</div><!-- /#main -->

css

.menu-parent{
	position: relative;
	background: #eee;
	width: 172px;
	height: 800px;
	float: left;
	}
.menu{
	position: absolute;
	top:0;
	}

jQuery

	$(window).scroll(function() {
		$("div.menu").each(function(){
			var menuTopMargin = 67;
			var parentY = $(this).parent().offset().top;
			var parentH = $(this).parent().height();
			var targetScrollValue = parentY - menuTopMargin;
			var wScrollvalue = $(window).scrollTop();
			var obj = {};
			$("span.test").text(parentY);
			if(wScrollvalue > targetScrollValue){
				if(wScrollvalue > (parentY + parentH) - (menuTopMargin +$(this).height()) ){
					obj = {
						position: "absolute",
						top: parentH - $(this).height()
						};
					}
				else{
					obj = {
						position: "fixed",
						top: menuTopMargin
						};
					}
				}
			else{
				obj = {
					position: "absolute",
					top: "0"
					};
				}
			$(this).css(obj); //cssを適用。
			})
		});
  • 条件分岐
    親の要素の座標とスクロール値から、条件を入れてその都度cssを適用しています。

Sample

5 Comments

  1. こんにちは。ステキなjQueryをありがとうございます!
    1つ質問なのですが、imgだとうまく動作しないのですが、
    imgに対しても適用できるようにするにはどうしたら良いでしょうか?
    教えていただけると幸いです。
    よろしくお願いいたします。

  2. Rさん、コメントありがとうございます。
    imgに直接適用せずに、一度divなどで囲ってみてはどうでしょうか。
    img(インライン要素)に指定できるcssは限られていますので、なるべくならdivなどのブロック要素で囲ってあげることをおすすめします。

  3. こんにちは。返信ありがとうございます!
    昨日出来なかったのですが、今日あらためてdivで囲ってやり直したら出来ました!
    やりたかったことが出来て感激です☆
    ありがとうございます。

    贅沢な質問(というかお願い)で恐縮なのですが、
    IE6にも適用できるようにすることは可能でしょうか。
    ページ上部か下部にならいるのですが、長いページだと途中でいなくなってしまうのです。
    すみません(>A<)

  4. すみません、当方、IE6で確認する環境がありませんが、IE6ではposition:absoluteがおかしくなるようですね。。。
    根本的な解決にはなりませんが、IE6だけ別処理をさせるようにしてはどうでしょうか。

    バージョン判別方法は下記サイトの方が詳しく説明してくれています。
    http://dx.24-7.co.jp/ie-hack/

    別処理の案としては、IE6では要素がついてくるのをあきらめ他の要素と一緒にスクロールするように、relativeにしておけば良いと思います。

    ご検討ください。

  5. こんにちは!ご連絡が遅くなりました。すみません。
    色々とありがとうございました!
    IEには何かしらやられます。。。
    勉強になりました。
    ありがとうございました!!

Leave a Reply

Back to Top