CSS3とjQueryで作る「開閉に合わせて×ボタンに変化させる」ハンバーガーメニュー
最近流行っている「開閉に合わせて×ボタンに変化させる」ハンバーガーメニューをCSS3とjQueryを使って再現してみました。
以前作成した「jQueryとCSS3でマテリアルデザインのハンバーガーメニュー」とソースが似ています。
※本ページは広告・アフィリエイトプログラムにより収益を得ています。
デモ・ソース
これだけじゃ「そもそも何だよそれ」って話だと思うので、デモを用意しました。百聞は一見に鹿ずって言いますもんね。
See the Pen Hamburger Navigation Menu by tokumewi (@tokumewi) on CodePen.
右上にある三本の線(ハンバーガーメニュー)をクリックすると、線が×の形に変化しながらグローバルナビゲーションが横からスライドして出てきます。
上手く見れない人のためにgifアニメにしてみました。
IE9ではCSSのtransition
に対応していないので、押した瞬間に形が変化します。
html
<div id="wrap">
<header>
<div class="inner">
<h1>SITE LOGO</h1>
<p class="navBtn">
<span></span>
<span></span>
<span></span>
</p>
<nav role='navigation'>
<ul>
<li><a href="#">Home</a></li>
<li><a href="#">About</a></li>
<li><a href="#">Product</a></li>
<li><a href="#">Works</a></li>
<li><a href="#">Links</a></li>
<li><a href="#">Contact Us</a></li>
</ul>
</nav>
<!-- /.inner --></div>
</header>
<div id="contents">
<p>コンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツ</p>
<p>コンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツ</p>
<p>コンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツ</p>
<p>コンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツコンテンツ</p>
<!-- /#contents --></div>
<!-- /#wrap --></div>
CSS
html, body, div, span, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
abbr, address, cite, code,
del, dfn, em, img, ins, kbd, q, samp,
small, strong, sub, sup, var,
b, i,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, dialog, figure, footer, header,
hgroup, menu, nav, section,
time, mark, audio, video {
-webkit-transition: 0.3s ease-in-out;
-moz-transition: 0.3s ease-in-out;
transition: 0.3s ease-in-out;
}
body {
font-family: 'Questrial', Verdana, "ヒラギノ角ゴ ProN W3", "Hiragino Kaku Gothic ProN", "メイリオ", Meiryo, sans-serif;
}
.fixed {
position:fixed;
top:0;
left:0;
width:100%;
}
h1 {
font-size:1.5em;
font-weight:bold;
}
/* オーバーレイ */
.overlay {
position: fixed;
top: 0;
left: 0;
display: none;
width: 100%;
height: 100%;
background: #000;
opacity: 0.7;
filter: alpha(opacity=70);
-ms-filter: "alpha(opacity=70)";
z-index: 999;
}
/* ヘッダー */
header {
position:fixed;
top:0;
left:0;
width:100%;
background:#fff;
box-shadow: 0 2px 5px rgba(0,0,0,0.26);
z-index:9999;
-webkit-user-select:none;
-moz-user-select:none;
user-select:none;
}
header .inner {
position:relative;
padding:1.5em;
-webkit-box-sizing:border-box;
-moz-box-sizing:border-box;
box-sizing:border-box;
}
/* ナビゲーション */
header nav {
overflow:auto;
position: fixed;
top: 0;
right: -70%;
width: 70%;
max-width:320px;
height: 100%;
background: #fff;
opacity: 0;
z-index:9999;
}
/* ナビゲーション:アクティブ時 */
header.navOpen nav {
opacity: 1;
right: 0;
}
header nav ul {
border-top:1px solid #ccc;
}
header nav ul li {
border-bottom:1px solid #ccc;
}
header nav ul li a {
position:relative;
display:block;
padding:1.5em;
color:#999;
text-decoration:none;
}
header nav ul li a:hover {
background:#f2f2f2;
}
header nav ul li a:before {
position: absolute;
top: 50%;
right: 1.5em;
display: inline-block;
content: "";
width: 7px;
height: 7px;
margin-top: -4px;
margin-right: -4px;
vertical-align: middle;
border-top: 3px solid #E60012;
border-right: 3px solid #E60012;
-webkit-transform: rotate(45deg);
transform: rotate(45deg);
-ms-transform: rotate(45deg);
}
/* ナビゲーションアイコン */
header .navBtn {
display: block;
width: 30px;
position: absolute;
top: 24px;
right: 15px;
cursor: pointer;
}
header .navBtn span {
display: block;
height: 4px;
width: 100%;
background: #E60012;
border-radius: 2px;
-webkit-transition: all .5s ease-in-out;
-moz-transition: all .5s ease-in-out;
transition: all .5s ease-in-out;
}
header .navBtn span:nth-of-type(2),
header .navBtn span:nth-of-type(3) {
margin-top: 5px;
}
/* ナビゲーションアイコン:アクティブ */
header.navOpen .navBtn span:nth-of-type(1) {
-webkit-transform: translateY(9px) translateX(0) rotate(45deg);
-ms-transform: translateY(9px) translateX(0) rotate(45deg);
transform: translateY(9px) translateX(0) rotate(45deg);
}
header.navOpen .navBtn span:nth-of-type(2) {
margin-top: 5px;
opacity: 0;
-webkit-transform: translateY(9px);
-ms-transform: translateY(9px);
transform: translateY(9px);
}
header.navOpen .navBtn span:nth-of-type(3) {
-webkit-transform: translateY(-9px) translateX(0) rotate(-45deg);
-ms-transform: translateY(-9px) translateX(0) rotate(-45deg);
transform: translateY(-9px) translateX(0) rotate(-45deg);
}
#contents {
margin-top:80px;
padding:1em 1.5em;
line-height:1.5;
}
#contents p {
margin-bottom:1em;
}
jQuery
// =========================================
// ナビゲーションアイコン
// =========================================
// オーバーレイ作成
$('#contents').prepend('<div class="overlay"></div>');
// アイコンをクリックしたら
$('.navBtn').click(function() {
$('header').toggleClass('navOpen'); // class付与/削除
$('#wrap').toggleClass('fixed'); // コンテンツを固定/解除
$('.overlay').toggle(); // オーバーレイ表示/非表示
// スマホナビゲーションがヘッダーに被らないようにする
var headerH = $('header').outerHeight();
if ($('header').hasClass('navOpen')) {
$('header nav').css('marginTop', headerH + 'px'); //ヘッダーの高さ分マージンを付ける
}
});
// オーバーレイをクリックしたら
$('.overlay').click(function() {
$(this).fadeOut(300); // オーバーレイ非表示
$('header').removeClass('navOpen'); // class削除
$('#wrap').removeClass('fixed'); // 固定解除
});
すごく適当な解説
やっていることはそこまで難しくなく、動作は主にCSS3のtransitionで、jQueryはclassを付けたり外したりしているだけです。あとはオーバーレイの動きを「ナビゲーションの開閉に応じて表示/非表示を切り替える」だけで作れます。
ナビゲーションの動きは、positionで右上に配置しておいてボタンが押されてclassが付与されたときだけright:-70%;
の値を0にしています。
/* ナビゲーション */
header nav {
overflow:auto;
position: fixed;
top: 0;
right: -70%;
width: 70%;
max-width:320px;
height: 100%;
background: #fff;
opacity: 0;
z-index:9999;
}
/* ナビゲーション:アクティブ時 */
header.navOpen nav {
opacity: 1;
right: 0;
}
ハンバーガーアイコンもコードが長いだけでやっていることは簡単です。3つあるに赤色のボーダーを付けて、2個め、3個めだけマージンを付けて間隔を空ける。
ナビゲーションがアクティブになったら、1つ目のボーダーを時計回りに45度傾けて9px下げる、3つ目はその逆で反時計回りに45度傾けて9px上げる、真ん中の線は9px下がりつつopacity
で透明にします。
/* ナビゲーションアイコン */
header .navBtn {
display: block;
width: 30px;
position: absolute;
top: 24px;
right: 15px;
cursor: pointer;
}
header .navBtn span {
display: block;
height: 4px;
width: 100%;
background: #E60012;
border-radius: 2px;
-webkit-transition: all .5s ease-in-out;
-moz-transition: all .5s ease-in-out;
transition: all .5s ease-in-out;
}
header .navBtn span:nth-of-type(2),
header .navBtn span:nth-of-type(3) {
margin-top: 5px;
}
/* ナビゲーションアイコン:アクティブ */
header.navOpen .navBtn span:nth-of-type(1) {
-webkit-transform: translateY(9px) translateX(0) rotate(45deg);
-ms-transform: translateY(9px) translateX(0) rotate(45deg);
transform: translateY(9px) translateX(0) rotate(45deg);
}
header.navOpen .navBtn span:nth-of-type(2) {
margin-top: 5px;
opacity: 0;
-webkit-transform: translateY(9px);
-ms-transform: translateY(9px);
transform: translateY(9px);
}
header.navOpen .navBtn span:nth-of-type(3) {
-webkit-transform: translateY(-9px) translateX(0) rotate(-45deg);
-ms-transform: translateY(-9px) translateX(0) rotate(-45deg);
transform: translateY(-9px) translateX(0) rotate(-45deg);
}
レスポンシブデザインでスマホ時のみハンバーガーメニューに
このままではPCでもいちいちハンバーガーメニューを開かないといけないので、PCでは横1行のナビゲーション、タブレットでは横2行にして、スマホになったときだけ先ほどと同じハンバーガーメニューにするようなレスポンシブデザインの例を作成してみました。
See the Pen Hamburger Navigation Menu(Responsive) by tokumewi (@tokumewi) on CodePen.
右上のEdit On CODEPENをクリックすると別窓で開きます。またはこちらからどうぞ。
CSS
html, body, div, span, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
abbr, address, cite, code,
del, dfn, em, img, ins, kbd, q, samp,
small, strong, sub, sup, var,
b, i,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, dialog, figure, footer, header,
hgroup, menu, nav, section,
time, mark, audio, video {
-webkit-transition: 0.3s ease-in-out;
-moz-transition: 0.3s ease-in-out;
transition: 0.3s ease-in-out;
}
.clearfix:before,
.clearfix:after {
content: " ";
display: table;
}
.clearfix:after {
clear: both;
}
.clearfix {
*zoom: 1;
}
body {
font-family: 'Questrial', Verdana, "ヒラギノ角ゴ ProN W3", "Hiragino Kaku Gothic ProN", "メイリオ", Meiryo, sans-serif;
}
.fixed {
position:fixed;
top:0;
left:0;
width:100%;
}
/* オーバーレイ */
.overlay {
position: fixed;
top: 0;
left: 0;
display: none;
width: 100%;
height: 100%;
background: #000;
opacity: 0.7;
filter: alpha(opacity=70);
-ms-filter: "alpha(opacity=70)";
z-index: 999;
}
/* ヘッダー */
header {
position:fixed;
top:0;
left:0;
width:100%;
background:#fff;
box-shadow: 0 2px 5px rgba(0,0,0,0.26);
z-index:9999;
-webkit-user-select:none;
-moz-user-select:none;
user-select:none;
}
header .inner {
position:relative;
max-width:1080px;
margin:0 auto;
padding:1.5em 0;
-webkit-box-sizing:border-box;
-moz-box-sizing:border-box;
box-sizing:border-box;
}
header h1 {
float:left;
width:20%;
margin-top: 1em;
font-size:1.5em;
font-weight:bold;
}
/* ナビゲーション */
header nav {
float:right;
width: 80%;
}
/* ナビゲーション:アクティブ時 */
header.navOpen nav {
opacity: 1;
right: 0;
}
header nav ul {
width: 100%;
border-top:1px solid #ccc;
}
header nav ul li {
float:left;
width: 16.6666%;
border-bottom:1px solid #ccc;
}
header nav ul li a {
position:relative;
display:block;
padding:1.5em;
color:#999;
text-decoration:none;
}
header nav ul li a:hover {
background:#f2f2f2;
}
header nav ul li a:before {
position: absolute;
top: 50%;
right: 1.5em;
display: inline-block;
content: "";
width: 7px;
height: 7px;
margin-top: -4px;
margin-right: -4px;
vertical-align: middle;
border-top: 3px solid #E60012;
border-right: 3px solid #E60012;
-webkit-transform: rotate(45deg);
transform: rotate(45deg);
-ms-transform: rotate(45deg);
}
/* ナビゲーションアイコン */
header .navBtn {
display: none;
width: 30px;
position: absolute;
top: 24px;
right: 15px;
cursor: pointer;
}
header .navBtn span {
display: block;
height: 4px;
width: 100%;
background: #E60012;
border-radius: 2px;
-webkit-transition: all .5s ease-in-out;
-moz-transition: all .5s ease-in-out;
transition: all .5s ease-in-out;
}
header .navBtn span:nth-of-type(2),
header .navBtn span:nth-of-type(3) {
margin-top: 5px;
}
/* ナビゲーションアイコン:アクティブ */
header.navOpen .navBtn span:nth-of-type(1) {
-webkit-transform: translateY(9px) translateX(0) rotate(45deg);
-ms-transform: translateY(9px) translateX(0) rotate(45deg);
transform: translateY(9px) translateX(0) rotate(45deg);
}
header.navOpen .navBtn span:nth-of-type(2) {
margin-top: 5px;
opacity: 0;
-webkit-transform: translateY(9px);
-ms-transform: translateY(9px);
transform: translateY(9px);
}
header.navOpen .navBtn span:nth-of-type(3) {
-webkit-transform: translateY(-9px) translateX(0) rotate(-45deg);
-ms-transform: translateY(-9px) translateX(0) rotate(-45deg);
transform: translateY(-9px) translateX(0) rotate(-45deg);
}
#contents {
max-width: 1080px;
margin:120px auto 0;
padding:1em 1.5em;
line-height:1.5;
}
#contents p {
margin-bottom:1em;
}
/* レスポンシブ */
@media screen and (max-width:1080px){
header .inner {
padding: 1.5em;
}
header h1 {
width: 30%;
margin-top: 0em;
}
header nav {
width:70%;
}
header nav ul li {
width: 33.333%;
}
#contents {
margin-top:180px;
}
}
@media screen and (max-width:640px){
header h1 {
width: auto;
margin-top: 0;
}
header .navBtn {
display:block;
}
header nav {
overflow:auto;
position: fixed;
top: 0;
right: -70%;
float:none;
width: 70%;
max-width:320px;
height: 100%;
background: #fff;
opacity: 0;
z-index:9999;
}
header nav ul li {
float: none;
width: auto;
}
#contents {
margin-top:80px;
}
}
jQuery
// ==============================================================
// ナビゲーションアイコン
// ==============================================================
// オーバーレイ作成
$('#contents').prepend('<div class="overlay"></div>');
// アイコンをクリックしたら
$('.navBtn').click(function() {
$('header').toggleClass('navOpen'); // class付与/削除
$('#wrap').toggleClass('fixed'); // コンテンツを固定/解除
$('.overlay').toggle(); // オーバーレイ表示/非表示
// スマホナビゲーションがヘッダーに被らないようにする
var headerH = $('header').outerHeight();
if ($('header').hasClass('navOpen')) {
$('header nav').css('marginTop', headerH + 'px'); //ヘッダーの高さ分マージンを付ける
}
});
// オーバーレイをクリックしたら
$('.overlay').click(function() {
$(this).fadeOut(300); // オーバーレイ非表示
$('header').removeClass('navOpen'); // class削除
$('#wrap').removeClass('fixed'); // 固定解除
});
// スマホサイズからPCになったとき
$(window).on('load resize', function() {
var breakpoint = 640;
if (window.innerWidth > breakpoint) {
$('header').removeClass('navOpen'); // class削除
$('#wrap').removeClass('fixed'); // 固定解除
$('.overlay').hide(); // オーバーレイ非表示
$('header nav').css('marginTop', 0 + 'px'); // マージン削除
}
});
まとめ
単なるナビゲーションでもナビゲーションのアイコンをちょっと工夫するだけで、サイトの印象が変わってきます。出来るだけシンプルにしたつもりなので、サイトに応じて適宜調整してみてください。
前略
鹿様
初めてコメントさせていただきます。現在私はウェブサイトを作成中ですが、スマートフォン対応のデザイン作成に苦慮している中、鹿様のサイトを拝見し、公開頂いている素晴らしいソースコードを拝見し感激しました。このサイトで紹介されているハンバーガーメニューのソースコードを私のサイトに使用させていただきたく、メッセージをお送りいたしました次第です。ご許可いただければ幸甚です。
草々
はじめまして。是非とも使ってやって下さい。そのためにサンプルを載せているので。今後ともよろしくお願いします。
ありがとうございます。今後ともよろしくお願い申し上げます。