サイドバーって画面をスクロールさせていくと最後のほうは何も表示されなくなっちゃいますよね。
せっかくスペースがあるなら常に何か表示させておきたいと思うものです。
そこで今回は画面をスクロールするとサイドバーが固定表示されるものを作ってみました。
仕様は以下の通りです。
- スクロールしたときにサイドバーが画面上部で固定表示される。
- ヘッダーが表示されているときはヘッダーと被らない。
- フッターが表示されているときはフッターと被らない。
サンプルコード
下に記載したコードは関係する部分だけを抜粋しています。
動くサンプルはこちらからどうぞ。
[btn class=”simple”]追従するサイドバーのサンプル[/btn]
HTML(関係ない部分は省いてます)
<!doctype html>
<html lang="ja">
<head></head>
<body>
<div id="container">
<header></header>
<nav id="headernav"></nav>
<div id="content">
<div id="inner-content" class="clearfix tuiju">
<main id="main" style="min-height: 1000px;">
<article>
<header>
<h1>jQueryテスト用</h1>
</header>
<section>
<input type="button" id="btna" value="ボタンA" />
</section>
<footer></footer>
</article>
</main>
<div id="sidebar" class="sideab">
<div class="sidetext">
<h4>新着情報</h4>
<div class="sidetextlist">
<ul>
<li><a href="https://swell.dev-lib.work">あいうえお</a></li>
<li><a href="https://swell.dev-lib.work">かきくけこ</a></li>
<li><a href="https://swell.dev-lib.work">さしすせそ</a></li>
<li><a href="https://swell.dev-lib.work">たちつてと</a></li>
<li><a href="https://swell.dev-lib.work">なにぬねの</a></li>
</ul>
</div>
</div><!-- /.sidetext -->
<div class="sidetext">
<h4>ランキング</h4>
<div class="sidetextlist">
<ul>
<li><a href="https://swell.dev-lib.work">あいうえお</a></li>
<li><a href="https://swell.dev-lib.work">かきくけこ</a></li>
<li><a href="https://swell.dev-lib.work">さしすせそ</a></li>
<li><a href="https://swell.dev-lib.work">たちつてと</a></li>
<li><a href="https://swell.dev-lib.work">なにぬねの</a></li>
</ul>
</div>
</div><!-- /.sidetext -->
<div class="sidetext">
<h4>カテゴリー</h4>
<div class="sidetextlist">
<ul>
<li><a href="https://swell.dev-lib.work">あいうえお</a></li>
<li><a href="https://swell.dev-lib.work">かきくけこ</a></li>
<li><a href="https://swell.dev-lib.work">さしすせそ</a></li>
<li><a href="https://swell.dev-lib.work">たちつてと</a></li>
<li><a href="https://swell.dev-lib.work">なにぬねの</a></li>
</ul>
</div>
</div><!-- /.sidetext -->
</div><!-- /#sidebar -->
</div><!-- /#inner-content -->
</div><!-- /#content -->
<footer id="footer"></footer>
</div><!-- /#container -->
</body>
</html>
CSS(関係ない部分は省いてます)
#sidebar {
width: 336px;
float: right;
}
#sidebar h4 {
margin-top: 0;
margin-bottom: 10px;
background-color: #04089b;
color: #FFFFFF;
padding: 5px 15px;
cursor: pointer;
}
#sidebar .sidetextlist ul {
padding: 0;
margin-top: 0;
}
#sidebar .sidetextlist li {
list-style: none;
}
#sidebar.sidefixed {
position: fixed;
top: 50px;
right: calc(50% - 580px);
}
#sidebar.sideab {
position: absolute;
bottom: 50px;
right: 0;
}
#inner-content.tuiju {
position: relative;
}
jQuery
<script type='text/javascript' src='//ajax.googleapis.com/ajax/libs/jquery/1.12.2/jquery.min.js?ver=1.12.2'></script>
<script type="text/javascript">
$(function(){
$(window).on('scroll resize', function() {
// スクロール位置
var scroll = $(document).scrollTop();
// コンテンツエリアのトップ
var contenttop = $("#content").offset().top;
// サイドバーの左位置
var sideleft = $("#sidebar").offset().left;
// サイドバーの高さ
var sideheight = $("#sidebar").outerHeight();
// サイドバーの上マージン
var sidemargintop = 50;
// サイドバーの下マージン
var sidemarginbottom = 50;
// フッターTOP位置
var footertop = $("#footer").offset().top;
if (scroll > (footertop - sidemarginbottom - sidemargintop - sideheight)) {
// フッターにあたった場合
$("#sidebar").css({
'position': 'absolute',
'top': 'auto',
'bottom': '50px',
'right': '0',
'width': '336px'
});
} else if (scroll > (contenttop - sidemargintop)) {
// 追従時
$("#sidebar").css({
'position': 'fixed',
'top': '50px',
'bottom': 'auto',
'right': 'calc(50% - 580px)',
'width': '336px'
});
} else {
// 追従するまでスクロールされてないとき
$("#sidebar").css({
'position': 'static',
'top': 'auto',
'bottom': 'auto',
'right': 'auto'
});
}
});
});
</script>
コード解説

ちょっと縦に潰れていますが、全体の構成は上の画像のような感じです。
そしてスクロールによって3つの状態ができます。
この3つの状態で表示位置のCSSのクラスを作成します。
1つ目、初期状態です。
ヘッダーが表示されている場合は通常の状態です。
ここではCSSは1~20のちょっとしたデザインのものだけです。
2つ目が、スクロールされてヘッダーが隠れたときからフッターが見えるまでです。
このときは、CSSの22~26行目(.sidefixed)が適用されます。
position: fixed; を指定すると、スクロール関係無しで固定位置に表示させることが出来ます。
right: calc(50% – 580px); これがちょっと珍しいですが、calc() というのを使うと計算できます。
ページの表示領域の横幅が1160pxを指定して作成しているので、半分の 580px をブラウザ全体の半分50%から引いています。
例えばブラウザの横幅が2000pxだったら 50% で1000pxになるので、1000-580=420pxとなります。
420pxというのは、画面の右端からページを構成するHTMLの右端までの距離です。
つまり、縦方向は上から50px固定で、横方向は元々サイドバーが表示されている場所と同じということになります。
そして、2つ目の状態になる条件ですが、ブラウザの上端がコンテンツエリア(メインとサイドバーのエリア)の上端より50px上まで来たときです。
ブラウザの上端はスクロール値とイコールですので6行目の var scroll = $(document).scrollTop(); で取得出来ます。
コンテンツエリアの上端は、var contenttop = $(“#content”).offset().top; で取得出来ます。
50pxは、追従するときにCSSで指定した24行目のtop: 50px と同じ値です。50pxにこだわりはありません。
そしてjQueryの29行目の条件判定をして、満たされれば .sidefixed をサイドバーのクラスに追加します。
3つ目の状態は、フッターとサイドバーが被らないように、フッターが見えたときには一緒にスクロールされるようにしたものです。
position: absolute; は基準位置からの位置指定です。
基準位置は、CSSの32行目でコンテンツエリア(メインとサイドバーのエリア)に対し position: relative; を指定しています。
bottom: 50px; right: 0; なので、右下から上に50px上がったところに固定されます。
条件は、画面の上端(スクロール位置)が、フッターの上端からサイドバーの高さ分上、更にサイドバー上下の余白(100px) 分上まで来たときです。
言葉で説明するのは分かり辛いかもしれません。
jQueryの20行目の条件になります。
これでコンテンツエリアの右下に固定されて一緒にスクロールされるようになります。
最後に、jQueryのif文ですが、下にスクロールしていくと現れる状態と逆から順番に条件を指定しています。
これは、else if というのは、条件に当てはまったら他の条件の処理は行わないというものだからです。
一番優先されるものから順番に条件を書いていくことになります。
まとめ
今回のポイントは、$(document).scrollTop(); によるスクロール位置の取得。
それと、offset() によるコンテンツの表示位置の取得ですね。
ただ、ここまで作りましたが、実はCSSだけでサイドバーの追従は出来るようです。
次回はCSSだけで作ってみようと思います。










コメント