追従するサイドバー
追従範囲を指定したサイドバーです。
resizeした時にも対応させていますので、サイドバーが突き抜けることはありません。
デモではわかりやすく各要素にheightを指定しています。
追従している時は.sideにfixedというクラスを、追従をやめたら.sideにstopというクラスが付きますのでstyle変更も容易です。
HTML
<header class="header">
<div class="headerInner">
<h1>header</h1>
<p>height:200px</p>
</div>
</header>
<div class="container">
<main class="main">
<div class="box"> height:1500px </div>
</main>
<div class="side">
<div class="sideInner">
<ul>
<li>メニュー <ul>
<li>小メニュー</li>
<li>小メニュー</li>
<li>小メニュー</li>
<li>小メニュー</li>
</ul>
</li>
<li>メニュー <ul>
<li>小メニュー</li>
<li>小メニュー</li>
<li>小メニュー</li>
<li>小メニュー</li>
</ul>
</li>
<li>メニュー <ul>
<li>小メニュー</li>
<li>小メニュー</li>
<li>小メニュー</li>
<li>小メニュー<br><br>height:600px</li>
</ul>
</li>
</ul>
</div>
</div>
</div>
<footer class="footer">
<div class="footerInner">
<h2>footer</h2>
<p>height:300px</p>
</div>
</footer>
CSS
body {
margin: 0;
padding: 0;
}
h1,
h2 {
margin: 0;
padding: 0;
}
ul {
margin: 0;
}
.header {
width: 100%;
height: 200px;
background: rgb(137, 249, 114);
}
.headerInner {
width: 100%;
max-width: 1000px;
margin: 0 auto;
padding: 10px 0;
box-sizing: border-box;
}
.container {
width: 100%;
max-width: 1000px;
margin: 0 auto;
display: table;
}
.main {
display: table-cell;
height: 1500px;
padding: 30px 0;
vertical-align: top;
box-sizing: border-box;
}
.footer {
width: 100%;
height: 300px;
background: rgb(137, 249, 114);
}
.footerInner {
width: 100%;
max-width: 1000px;
margin: 0 auto;
padding: 10px 0;
box-sizing: border-box;
}
/*===================== side =====================*/
.side {
display: table-cell;
width: 300px;
padding: 30px 0;
vertical-align: top;
box-sizing: border-box;
}
.sideWrap {
position: relative;
width: 300px;
height: 100%;
padding: 0;
}
.sideInner {
width: 330px;
height: 600px;
background: #ddd;
margin: 0 auto;
box-sizing: border-box;
}
.sideInner.fixed {
position: fixed;
top: 30px;
}
.side {
display: table-cell;
width: 330px;
max-width: 330px;
box-sizing: border-box;
vertical-align: top;
background: #808080;
}
javascript(jQuery)
function sideFixed() {
var sideInner = jQuery('.sideInner');
var side = jQuery('.side');
// sideのtop位置を取得
var sideOffsetTop = side.offset().top;
//sideの高さ
var sideHeight = jQuery('.side').outerHeight();
//sideInnerの高さ
var sideInnerHeight = jQuery('.sideInner').outerHeight();
//sideの下計算
//sideの高さ + sideのtop開始位置 - ( sideInnerの高さ +[ sideのpadding-bottom:30px + .sideInner.fixedのtop:30px分 ] )
//1500 + 200 - ( 600 + 60 ) = 1140
//1140pxスクロールしたら追従をやめる
var sideBottom = sideHeight + sideOffsetTop - (sideInnerHeight + 60);
jQuery(function() {
function scrollPc() {
var topScroll = jQuery(window).scrollTop();
if (topScroll > sideOffsetTop && topScroll < sideBottom) {
//スクロール値がsideのtop位置よりも大きい時かつ、
//スクロール値が1140pxよりも小さい時
// fixed
sideInner.addClass('fixed');
sideInner.removeClass('stop');
side.css('vertical-align', 'top');
} else if (topScroll > sideOffsetTop && topScroll >= sideBottom) {
//スクロール値がsideのtop位置よりも大きい時かつ、
//スクロール値が1140pxと等しい、または大きい時
//stop
sideInner.removeClass('fixed');
sideInner.addClass('stop');
//table-cellなのでvertical-alignを使えます
side.css('vertical-align', 'bottom');
} else {
//上記に当てはまらないもの
//(スクロール値がsideのtop位置よりも小さい時)
// top
sideInner.removeClass('fixed');
sideInner.removeClass('stop');
side.css('vertical-align', 'top');
}
return false;
}
scrollPc();
//スクロールした時に実行
jQuery(window).scroll(function() {
scrollPc();
});
});
}
//loadとresizeした時に実行
jQuery(function() {
jQuery(window).on('load resize', function() {
sideFixed();
});
});
スクロールの値に応じて3段階に分ける
最初~header通過まで
最初は追従せずに、そのまま表示。
header通過~footer上30pxまで
headerを過ぎたらposition:fixedで追従させる。
side.offset().top;でsideのtop位置を取得できます。
この領域に来たら.sideInnerにfixedのclassを付けます。
footer上30pxから~最後
このままfixedだと突き抜けてしまうので、footer上30pxまで来たら追従をストップしたい。
ブラウザの一番上から、footer上30pxまでの高さが分かればいい。
今回はsideの高さ + sideのtop開始位置 – ( sideInnerの高さ + sideのpadding-bottom:30px + .sideInner.fixedのtop:30px分 )で計算しました。
sideのpadding-bottom:30pxと、追従しているときに.sideInnerのtopを30px開けていますので、2つ合わせて60pxです。
cssで.containerはdisplay:tableに、.mainと.sideはdisplay:table-cellにしてあるので、高さを求めるのが容易です。
この領域に来たらs.ideInnerにstopのclassを付けます。
また.sideはdisplay:table-cellのため、vertical-alignを使えますのでbottomにして下揃えにします。