WEBOPIXEL

レスポンシブでハンバーガーメニューになる固定サイドバー

Posted: 2017.09.21 / Category: HTML&CSS, javascript / Tag: 

近年ではモニターサイズが広くなってきた影響もあり、サイドバーを固定表示させてるサイトが多くみられるようになった気がします。
そこでここでは画面が狭くなるとハンバーガメニューになるレスポンシブに対応した固定サイドバーの作成方法をご紹介します。

Sponsored Link

ロゴがナビゲーションに含まれる・マウスオーバーでサブメニュー開閉タイプ

ロゴもサイドバーに含むレイアウトで、サブメニューがある場合はマウスオーバーすると右に表示するタイプです。

HTML

幅を狭めた時にはロゴ部分とメニューは別にしたかったので、構造的に分けてCSSで調節するようにします。

html

<header id="global-head">
	<h1 id="brand-logo">Logo</h1>
</header>

<div id="nav-toggle">
	<div>
		<span></span>
		<span></span>
		<span></span>
	</div>
</div>

<aside id="sidebar">
	<nav id="global-nav">
		<ul>
			<li><a href="#">Home</a></li>
			<li class="sub-menu">
				<a href="#" class="sub-menu-head">About</a>
				<ul class="sub-menu-nav">
					<li><a href="#">About 1</a></li>
					<li><a href="#">About 2</a></li>
					<li><a href="#">About 3</a></li>
				</ul>
			</li>
			<li class="sub-menu">
				<a href="#" class="sub-menu-head">Products</a>
				<ul class="sub-menu-nav">
					<li><a href="#">Product 1</a></li>
					<li><a href="#">Product 2</a></li>
					<li><a href="#">Product 3</a></li>
				</ul>
			</li>
			<li><a href="#">Link</a></li>
			<li><a href="#">Contact</a></li>
		</ul>
	</nav>
</aside>

<main id="main">
	<div id="main-in">
		<div id="main-visual">
			<h2>Fixed Sidebar</h2>
		</div>
	</div><!-- /#main-in -->
</main>

<div id="overlay"></div>

CSS

CSSは長いので主要部分だけピックアップします。
完全版はサンプルをご覧ください。

css

#global-head {
	position: fixed;
	color: #033560;
	width: 260px;
	text-align: center;
	padding-top: 60px;
	z-index: 100;
}

#sidebar {
	font-size: 15px;
	padding-top: 120px;
	width: 260px;
	height: 100%;
	position: fixed;
	color: #033560;
	background: #fff;
	text-align: center;
}

#global-nav ul {
	list-style: none;
	margin-left: 0;
}
#global-nav > ul > li {
	position: relative;
}

#global-nav a {
	color: #033560;
	text-decoration: none;
	display: block;
	padding: 15px 0;
	transition: background-color .3s linear;
}

/* sub-menu */
#global-nav .sub-menu-nav {
	position: fixed;
	background: #033560;
	color: #fff;
	top: 0;
	padding-top: 90px;
	left: 260px;
	width: 0;
	height: 100%;
	overflow: hidden;
	transition: width .2s ease-out;
}
#global-nav .sub-menu-nav a,
#global-nav .sub-menu:hover .sub-menu-nav {
	width: 230px;
}

/* nav-toggle */
#nav-toggle {
	display: none;
	position: fixed;
	top: 15px;
	right: 15px;
	height: 32px;
}

#overlay {
	display: none;
	position: fixed;
	background: rgba(0,0,0,.6);
	width: 100%;
	height: 100%;
	top: 0;
	left: 0;
	right: 0;
	bottom: 0;
}


@media screen and (max-width: 900px) {
	#main-in {
		padding-left: 0;
	}

	#global-head {
		width: 100%;
		padding: 10px;
		background: rgba(255,255,255,.8);
		display: flex;
	}

	#sidebar {
		position: fixed;
		right: -300px;
		top: 0;
		height: 100%;
		width: 300px;
		color: #333;
		background: #fff;
		transition: .35s ease-in-out;
	}

	/* サブメニューは開けない */
	#global-nav .sub-menu-head:after,
	#global-nav .sub-menu-nav {
		display: none;
	}
	#nav-toggle {
		display: block;
	}

	/* nav open */
	.open {
		overflow: hidden;
	}
	.open #overlay {
		display: block;
	}
	.open #sidebar  {
		transform: translate3d(-300px,0,0);
	}

	/* #nav-toggle close */
	.open #nav-toggle span:nth-child(1) {
		top: 11px;
		transform: rotate(45deg);
	}
	.open #nav-toggle span:nth-child(2) {
		width: 0;
		left: 50%;
	}
	.open #nav-toggle span:nth-child(3) {
		top: 11px;
		transform: rotate(-45deg);
	}

	/* z-index */
	#overlay {
		z-index: 200;
	}
	#sidebar {
		z-index: 300;
	}
	#nav-toggle {
		z-index: 400;
	}
}
28〜51行目
サブメニューはスライドアニメーションで表示させたかったので、.sub-menu-navにはoverflow: hidden;、直下のaタグにはwidthを指定してます。
スライドなのでleftとかでアニメーションさせればよさそうですが、重なりの関係などもあったりするので、.sub-menu-navのホーバーでwidthをアニメーションさせてます。
77行目
ここからは主にタブレット以下のサイズを想定してますので、マウスオーバーで表示していたサブメニューは非表示にしてます。

JavaScript

最後にJavaScriptです。
サブメニューの開閉自体はマウスオーバーなのでCSSでやってるのですが、開いている親のボタンをアクティブにしておきたかったので、そこはjQueryでやってます。
あとはハンバーガーメニューの開閉ですね。
これくらいだったらjQuery入れない選択もありですが、やっぱり楽かなとか。

JavaScript

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.12.3/jquery.min.js"></script>
<script type="text/javascript">
(function($) {
    $(function () {
        $('.sub-menu').on({
            'mouseenter': function () {
                $(this).addClass('is-active');
            },
            'mouseleave': function () {
                $(this).removeClass('is-active');
            }
        });
        $('#nav-toggle,#overlay').on('click', function() {
            $('body').toggleClass('open');
        });
    });
})(jQuery);
</script>

ロゴはコンテンツ側・サブメニューがアコーディオンのタイプ

ヘッダーはコンテンツ側についていて、サブメニューを閉じるとコンテンツ幅が広がって閉じるタイプです。

html

<div id="nav-toggle">
	<div>
		<span></span>
		<span></span>
		<span></span>
	</div>
</div>

<aside id="sidebar" class="scroll">
	<nav id="global-nav">
		<ul>
			<li><a href="#">Home</a></li>
			<li class="sub-menu">
				<a href="#" class="sub-menu-head">About</a>
				<ul class="sub-menu-nav">
					<li><a href="#">About 1</a></li>
					<li><a href="#">About 2</a></li>
				</ul>
			</li>
			<li class="sub-menu">
				<a href="#" class="sub-menu-head">Products</a>
				<ul class="sub-menu-nav">
					<li><a href="#">Product 1</a></li>
					<li><a href="#">Product 2</a></li>
				</ul>
			</li>
			<li><a href="#">Link</a></li>
			<li><a href="#">Contact</a></li>
		</ul>
	</nav>
</aside>


<div id="container">
	<header id="global-head">
		<h1 id="brand-logo">Logo</h1>
	</header>

	<main id="main">
		<div id="main-visual">
			<h2>Fixed Sidebar</h2>
		</div>
		<section class="inner">
		</section>
	</main>
</div><!-- /#container -->

サブメニューをアコーディオンにする場合は画面にコンテンツ量によっては画面に収まらない可能性がありますので、スクロールバーを入れるのがスタンダードです。
Perfect Scrollbarはバーをいい感じにしてくれます。
あとアコーディオン動作にはVelocity.jsを使用してます。

JavaScript

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.12.3/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.5.0/velocity.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.perfect-scrollbar/0.8.1/js/perfect-scrollbar.jquery.min.js"></script>
<script type="text/javascript">
(function($) {
    $(function () {

        // サイドサブメニューアコーディオン
        $('.sub-menu-head').on('click', function(){
            var $subNav = $(this).next('.sub-menu-nav');
            if ($subNav.is(':visible')) {
                $subNav.velocity('slideUp', {duration: 200});
                $(this).parent('li').removeClass('is-active');
            }
            else {
                $subNav.velocity('slideDown', {duration: 200});
                $(this).parent('li').addClass('is-active');
            }
            return false;
        });

        $('#nav-toggle').on('click', function() {
            $('body').toggleClass('close');
        });

        $('.scroll').perfectScrollbar();
    });
})(jQuery);
</script>

書いてて全然意味わかんなくなってきましたが以上です。