【プラグインなし!】レスポンシブにサイドバーを下で固定する実装方法をご紹介
Web2018年3月9日
よくブログで実装されているイメージですが、企業サイトなどでもページをある程度スクロールすると、サイドバーが固定されているのをご覧になったことがあるかと思います。サイトの基本設計やサイドバーを上下どちらに固定するかなどで実装方法は様々ですが、今回Web屋の芝生DIYでは「サイドバーを下に固定」する実装を行いました。
そこで本記事では、「プラグインを使用せずレスポンシブにサイドバーを下に固定する実装方法」についてご紹介させていただきたいと思います。
サンプルソース
html
<header>
<!--ヘッダー要素-->
</header>
<div id="content">
<main>
<div id="main-inner">
<!--メインコンテンツ要素-->
</div>
</main>
<div id="nav-sidebar">
<div id="nav-sidebar-inner">
<!--サイドバー要素-->
</div>
</div>
</div><!--/#content-->
<footer>
<!--フッター要素-->
</footer>
css
//ヘッダーのcssを定義
header{
}
//フッターのcssを定義
footer{
}
//コンテンツ全体のcssを定義(max-widthなど)
#content{
}
//メインカラムのcssを定義(float:left;やwidth:XXXなど)
#content main{
}
//メインカラムのcssを定義(余白調整や角丸など)
#content main #main-inner{
}
//サイドバー全体のcssを定義(float:right;やwidth:XXXなど)
div#nav-sidebar{
}
//スクロール固定中のclass
div#nav-sidebar-inner.fixed-side{
position:fixed;
bottom:0;
}
//フッターに到達時のclass
div#nav-sidebar-inner.bottom-side{
position:absolute;
}
//メディアクエリ(1カラム時はposition:static)
@media screen and (max-width:850px){
div#nav-sidebar-inner.fixed-side{
position:static;
}
div#nav-sidebar-inner.bottom-side{
position:static;
}
}
js
(function(){
$(window).on("load scroll resize",function(){
var sidebarFix = function(){
//スクロールバー込みの画面幅
var w = window.innerWidth;
//サイドバー有無の境界幅
var x = 851;
if(w >= x){
//各要素の高さを取得
var $winH = $(window).height();//ウィンドウの高さ
var $pageH = $('body').height();//bodyの高さ
var $headerH = $('header').outerHeight(true);//ヘッダーの高さ
var $mainH = $('#main-inner').outerHeight(true);//メインカラムの高さ
var $sideH = $('#nav-sidebar-inner').outerHeight(true);//サイドバーの高さ
var $footerH = $('footer').outerHeight(true);//フッターの高さ
var $paddingH = $('#content').outerHeight(true) - $('#content').height();//余白の高さ
//サイドバーの固定と解除条件を計算
var $fixedSide = ($headerH + $paddingH + $sideH) - $winH;//サイドバーを固定するスクロール高さ
var $scrollBtm = $pageH - $winH - $footerH ;//フッターが画面に表示されるスクロール高さ
//スクロール値を取得
var $scrollTop = $(this).scrollTop();
//記事がサイドバーより長い場合実行
if($mainH > $sideH){
//サイドバー下端までスクロールしたらサイドバー下端で追従
if($scrollTop > $fixedSide){
//サイドバー固定のクラス付与
$('#nav-sidebar-inner').addClass('fixed-side').css('bottom',0);
//サイドバー固定時のサイドバー幅を計算
var $sidebarW = $('#nav-sidebar').width();
//計算したサイドバー幅を付与
$('#nav-sidebar-inner').css("width",$sidebarW);
//条件から外れたら固定クラスを削除し幅をリセット
}else{
//サイドバー固定のクラス削除
$('#nav-sidebar-inner').removeClass('fixed-side');
//サイドバー幅リセット
$('#nav-sidebar-inner').css('width','auto');
}
//フッターまでスクロールしたらサイドバー下端をフッター上端に連結
if($scrollTop > $scrollBtm){
$('#nav-sidebar-inner').removeClass('fixed-side').css('bottom',0);
$('#nav-sidebar-inner').addClass('bottom-side').css('bottom',$footerH);
//条件から外れたらクラスを削除
}else{
$('#nav-sidebar-inner').removeClass('bottom-side').css('bottom',0);
}
}
//サイドバーがない場合に適用
}else{
$('#nav-sidebar-inner').css('width','auto');
}
};sidebarFix();
});
})(jQuery);
解説
実装に当たって、以下の記事を参考にさせていただきました。
まずは変数wにスクロールバー込みの画面幅を格納し、変数xではサイドバー固定を実行するブレイクポイントを定義します。次に「if(w >= x){~」で、「ブレイクポイントよりも画面幅が大きい場合」のみ、サイドバー固定を実行する条件分岐を行います。
if文の中で、サイドバー固定の計算に必要な各要素の値を変数に格納します。続けて、変数$fixedSideには「ヘッダー + コンテンツ全体の余白 + サイドバー」を足した値からウインドウの高さを引くことで、サイドバーを固定するスクロールの高さを定義します。さらに、変数$scrollBtmにはbodyからウインドウとフッターの高さを引くことで、フッター到達時にサイドバーがフッター上部で固定するスクロールの高さを定義しています。
続けて、実際にサイドバーを固定する処理の記述になります。そもそもメインカラムがサイドバーより短い場合はサイドバー固定を実行する必要はないので、「if($mainH > $sideH){~」でさらに条件分岐し、処理を行います。
if($scrollTop > $fixedSide){~にてフッター上部までサイドバー固定用のcssを付与します。ポイントは、#nav-sidebar-innerにwidthを設定する点です。#nav-sidebar-innerはposition:fixedになるため、包括している#nav-sidebarのwidthが適用されなくなり幅が変わってしまいます。そのため、#nav-sidebarのwidthを#nav-sidebar-innerにも適用してあげる必要があります。
else{~では付与したclassを外し、widthの値もautoにリセットします。
if($scrollTop > $scrollBtm){~にて、フッター到達時の処理を行います。サイドバー固定用のclassを外し、フッター到達時用のclassを付与します。ポイントは、レスポンシブでフッターの高さが可変になることを考慮し、固定値ではなく変数$footerHに格納しておいたフッターの高さをbottomに付与する点です。これにより、レスポンシブに対応したサイドバー固定が可能になります。
最後に、条件から外れた場合はフッター到達時のclassを外します。
まとめ
ブログ記事はそこまで内容が短いものでなければ、サイドバーよりメインコンテンツが長くなるケースが多いかと思いますが、ある程度スクロールすれば当然サイドバーには何もなくなります。そんな時、サイドバー固定を実装しておくことで、空いたスペースを有効活用することが可能になります。
ご紹介した方法は、プラグインも使用せずレスポンシブにも対応しているので非常におすすめです。サイトの設計に応じてセレクタ指定やブレイクポイントは多少弄ぶ必要はありますが、なるべく汎用的なソースとしてご紹介させていただきました。ぜひご参考にしていただければ幸いです。