サイトロゴ

Enjoy Creating
Web & Mobile Apps

MENU BOX
WEB
MOBILE
OPEN

ホーム

 > 

 > 

【JavaScript】ハンバーガーメニューの基本的な動きを実装してみよう!

【JavaScript】ハンバーガーメニューの基本的な動きを実装してみよう!

この記事にはプロモーションが含まれています。

Webデザイン・UIデザイン面においては、ボタンやタブなどがクリック(タップ)された時の動きをコントロールする目的でJavaScriptが使用されることが多いかと思います。

その代表例がハンバーガーメニューでしょう。

 用語解説:ハンバーガーメニューとは?

ハンバーガーメニューのサンプルイメージ

UIデザインの視点からすれば、ハンバーガーメニューには批判的な意見もあります()が、筆者の感覚では既にメニュー表示のボタンとして広く浸透しつつあるボタンだと思います。
なので、今後もWebサイト制作などにおいてハンバーガーメニューの実装は欠かせないものと言えるでしょう。
※見た目ではメニュー表示ボタンだと分かりづらいなど

そこで今回は、ハンバーガーメニューを例に、
・要素がクリック(タップ)されたことをチェックするプログラム
・classを付け足したり、外したりするプログラム

を簡単に説明していきます。

– 目次 –

ハンバーガーメニューの動きの基本

実際にJavaScriptプログラムを書き始める前に、まずそもそもハンバーガーメニューはどういった動きで構成されているか?を整理しておきましょう。

ハンバーガーメニューの動きとしては、以下のようなステップになっています。

ハンバーガーメニューの動き

  1. ハンバーガーメニューをタップするハンバーガーメニューの画像
  2. ハンバーガーメニューの三本線が「×」に切り替わるハンバーガーメニューの×印画像
  3. ナビゲーションメニューが現れるハンバーガーメニューのメニュー表示画像
  4. もう一度ハンバーガーメニューをタップするとメニューが消える(ボタン表示も×から三本線に戻る)ハンバーガーメニューの画像

つまり、ハンバーガーメニューの実装には以下のポイントを押さえる必要がありそうですね。

ハンバーガーメニュー実装のポイント

  1. 普段はナビゲーションメニューを隠しておく
  2. メニューボタンがタップされたことを検知する
  3. タップを検知したら隠しておいたメニューを表示させる
  4. もう一度タップされたら元の状態に戻るようにする

こうして整理してみると想像できると思いますが、ハンバーガーメニューの実装はJavaScriptだけでなくCSSの力も借りないと難しいと言えます。

普段の状態でナビゲーションメニューを隠しておくには、CSSのpositionプロパティを使って画面外に移動させたり、opacityプロパティで不透明度を0にしておいたりする必要がありそうです。

このように、特にWeb/UIデザインにおいてはJavaScriptとCSSは密接な関係にあります。

JavaScriptとHTML/CSSを学ぶ順番に掟や鉄則があるわけではないですが、機能の開発ではなく、デザインの方面に興味がある場合は先にCSSを理解しておいた方が良いかもしれません。
そうすると、必然的に「CSSだけでは実装が難しいこと」が分かるようになります。

それが分かれば、自分にとって必要なJavaScriptの学習範囲をピンポイントで絞れるようになるため、効率的に進められると思います。

    POINT!
  1. ・ハンバーガーメニューは、メニューボタンタップ→メニュー表示→もう一度タップで元に戻るという動きになっている!
  2. ・ハンバーガーメニューの実装にはCSSも駆使する必要がある!
  3. ・Web/UIデザインに興味が強い場合は、JavaScriptの前にCSSを先に理解しておくとスムーズ(かも)!

メニューが非表示の状態を用意する

前章で流れを確認した通り、第一段階である『ハンバーガーメニューボタンがタップ(クリック)される前』は、メニューが隠された状態です。
よって、まずはその状態を準備していくことにしましょう。

なお、本記事はJavaScriptに関する記事ですがこの章に関してはCSSのみで準備を進めていきます。

ナビゲーションメニューの隠し方はいろいろありますが、今回は画面の左端のさらに左奥に隠しておくと言う方法で隠しておくこととします。

以下はサンプルコードです。
便宜上、全体をdivタグでマークアップし、content_bodyというclass名をつけて幅と高さを指定しています。(以降、これを仮想ボディと呼ぶこととします)

HTML※スクロールできます

<body>
	<div class="content_body">
		<header>
			<div>
				<h1>サイトタイトル</h1>
			</div>
		</header>
		<nav class="sample_sp_menu">
			<ul>
				<li>HOME</li>
				<li>ABOUT</li>
				<li>NEWS</li>
				<li>CONTACT</li>
			</ul>
		</nav>
		<section>
			<div>
				<p>ここにキャッチコピーが入ります。</p>   
			</div>
		</section>
	</div>
</body>

CSS※スクロールできます

body {
	margin: 0;
}
.content_body {
	width: 300px;
	height: 500px;
	background: lightgrey;
	position: relative;
}
.content_body header {
	position: relative;
	background-color: black;
	color: white;
	z-index: 1;
	height: 80px;
	display: flex;
	align-items: center;
	padding-left: 20px;
}
.content_body header div {
	height: fit-content;
}
.content_body h1 {
	font-size: 1rem;
}
.content_body section {
	height: 420px;
	display: grid;
	justify-content: center;
	align-content: center;
}
.sample_sp_menu {
	background-color: rgba(0,0,0,.5);
	position: absolute;
	top: 0;
	left: -300px;
	width: 100%;
	height: 100%;
	display: grid;
	justify-content: center;
	align-content: center;
	color: white;
	text-align: center;
	transition: .5s;
}
.sample_sp_menu ul {
	padding-inline: 0;
}
.sample_sp_menu li {
	list-style: none;
	margin-top: 1.5rem;
	cursor: pointer;
}

ポイントは、ナビゲーションメニューを仮想ボディの横幅と同じ幅だけpositionプロパティで左にずらし、見えなくしているという点です。
上記のサンプルコードをWebブラウザで表示させると下のような状態になります。

上記サンプルコードの表示結果

背景が黒のところがヘッダーで、その下のグレーの部分がコンテンツ部分です。
そして、上の画像ではナビゲーションメニュー(navタグでマークアップしている部分)はブラウザ画面左端の奥に隠れている状態です。

left: -300px;を解除すると下のような表示になります。

上記サンプルコードの表示結果その2

サンプルなので、メニューにaタグによるリンク設定がされてないなどのツッコミどころはありますが、下準備はこれでOKです。

なお、ナビゲーションメニューを隠す方法としてopacityプロパティで不透明度を指定する方法もよく用いられますが、不透明度を0にするだけでは不十分です。

と言うのも、不透明度を0にしても要素は存在している上に、リンクをタップできてしまうからです。

要素を透明にして隠したい場合は要素の不透明度を0にするだけでなく、幅や高さも0にするなど、メニューリンクがタップできないようにしておく必要があります。

    POINT!
  1. ・ハンバーガーメニュー実装の第一段階目は、ナビゲーションメニューが隠れた状態を用意!
  2. ・メニューを隠す方法は、画面外に移動させたり不透明度を変えたりする方法がある!
  3. ・ただし不透明度を0にするだけではナビゲーションメニューのリンクがタップできてしまうので、他の調整も必要!

メニューボタンにクリックイベントを設定する

下準備ができたら次はメニューボタンを用意して、メニューボタンにクリックイベントを設定していきます。
なお、クリックイベントはタブレットやスマホにおけるタップにも反応するようになっています。

まずはハンバーガーボタンの設置ですが、大きく分けて2つの方法があります。

1つはハンバーガーボタンの画像を用意して画像表示を切り替える方法。
そしてもう1つが、CSSで用意してアニメーションで切り替える方法です。

どちらが良いとか優れているというのはありませんが、簡単なのは画像で切り替える方法です。

下のサンプルは画像ではなく、CSSアニメーションで切り替えているハンバーガーボタンのサンプルです。
動きがあって面白いのですが、その分必要なCSS調整が増えるため、実装の難易度は少しだけ高くなると言えます。

▼試しにクリック(タップ)してみてください

ですが今回はコードをシンプルにするために、画像で切り替える方法を採用したいと思います。
具体的には▼下のような感じです。(タップしてみてください)

画像で切り替えるには、当然ですがハンバーガーボタンの画像を用意しなければなりません。
Illustratorでサクッと作るか、フリーアイコン素材などを利用すると良いでしょう。

ここでは以下の2種類の画像を用意しました。

ハンバーガーボタンサンプル画像1 ハンバーガーボタンサンプル画像2

この2つの画像をヘッダー部分に配置し、片方の画像(×印の方)はopacityプロパティで隠しておきます。
また、2つの画像がぴったり重なるように、positionプロパティで調整を行います。

前章で紹介したコードに追記・改変していきましょう。

HTML※スクロールできます

<body>
	<div class="content_body">
		<header>
			<div class="header_container">
				<div class="menu_container">
					<img class="menu_open" src="img/ham-menu-image01.png">
					<img class="menu_close" src="img/ham-menu-image02.png">    
				</div>
				<h1>サイトタイトル</h1>
			</div>
		</header>
		<nav class="sample_sp_menu">
			<ul>
				<li>HOME</li>
				<li>ABOUT</li>
				<li>NEWS</li>
				<li>CONTACT</li>
			</ul>
		</nav>
		<section>
			<div>
				<p>ここにキャッチコピーが入ります。</p>
			</div>
		</section>
	</div>
</body>

CSS※スクロールできます

body {
	margin: 0;
}
.content_body {
	width: 300px;
	height: 500px;
	background: lightgrey;
	position: relative;
}
.content_body header {
	position: relative;
	background-color: black;
	color: white;
	z-index: 1;
	height: 80px;
}
.header_container {
	width: 100%;
	height: 100%;
	position: relative;
}
.header_container h1 {
	font-size: 1rem;
	width: fit-content;
	position: absolute;
	top: calc( 50% - .8rem);
	left: 0;
	right: 0;
	margin: auto;
}
.menu_container {
	width: 50px;
	height: 50px;
	position: absolute;
	top: calc(50% - 25px);
	left: 20px;
			cursor: pointer;
}
.menu_container img {
	width: 100%;
	filter: invert(1);
	position: absolute;
	top: 0;
	left: 0;
}
	.menu_open {
		opacity: 1;
	}
	.menu_close {
		opacity: 0;
	}
.content_body section {
	height: 420px;
	display: grid;
	justify-content: center;
	align-content: center;
}
.sample_sp_menu {
	background-color: rgba(0,0,0,.5);
	position: absolute;
	top: 0;
	left: -300px;
	width: 100%;
	height: 100%;
	display: grid;
	justify-content: center;
	align-content: center;
	color: white;
	text-align: center;
	transition: .5s;
}
.sample_sp_menu ul {
	padding-inline: 0;
}
.sample_sp_menu li {
	list-style: none;
	margin-top: 1.5rem;
	cursor: pointer;
}

img要素に対して、filter: invert(1);と指定していますが、これは黒色で作ってしまった画像を白に反転させたかったからです。
元々白色で用意しておけばこのCSS調整は必要ありません。(画像を別で用意する方が面倒くさかっただけです)

上のサンプルコードをブラウザで表示させると▼下のようになります。

上記サンプルコードの表示結果

これでホッと一息…といきたいところですが、まだクリックイベントの設定ができていません。
ここでようやくJavaScriptの出番がやってきます。

クリックイベントを検知するには、JavaScriptのElement.addEventListener(‘click’, 〜)を使用します。

クリックを検知したい要素の情報を取得した上で、addEventListener(‘click’, 〜)を記述することによって要素のクリックイベントを監視・コントロールすることができます。

上記のサンプルコードでは、ハンバーガーボタンを格納している要素に、menu_containerというclass名をつけていましたね。
その要素情報をquerySelectorメソッドなどで取得し、クリックイベントのイベントリスナーを設定してみましょう。

const MenuContainer = document.querySelector('.menu_container');    
	MenuContainer.addEventListener('click', () => {
		alert('クリックされました。');
	});

さて、ここでアロー関数というものが出てきています。
※( => の部分です)

アロー関数とは一言で言えば、プログラムコードを簡素化して短く書ける仕組みです。

アロー関数については、慣れないうちに完璧に理解しようとすると深みにハマりやすいポイントです。
なので、最初のうちは『こんなふうに書けば良いんだな』という程度に理解しておくと良いかなと思います。

『どうしても詳しく知りたい!』という方は、MDNのサイトの解説がおすすめです。
MDNのアロー関数に関するページは▼こちらからどうそ。(別タブで開きます)
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Functions/Arrow_functions

下のサンプルはクリックされたらアラート(お知らせ)が出るボタンです。
プログラムは先ほど紹介したものと全く同じで、クリックイベントを検知できていることが確認できます。

あとはこの仕組みを利用して、メニューボタンがクリック(タップ)されることで画像を切り替えたり、ナビゲーションメニューの表示・非表示を切り替えたりできるようにしていきます。

    POINT!
  1. ・ハンバーガーボタンはCSSで設置する場合と、画像で設置する場合がある!
  2. ・簡単(コードが少なくて済む)のは画像で設置する方法!
  3. ・クリックイベントは、Element.addEventListener(‘click’ 〜)で検知・コントロールできる!

クリックでclassを追加・削除

クリックイベントによって要素の表示や見た目を変えるには、要素のclassを追加したり外したりすると簡単にできます。

例えば、普段は黒い文字色にしておき、クリックされると赤い文字色に変化させたい場合で考えてみましょう。
クリックされる前は、【 sample_text 】というclassのみ持つものとします。

その場合、CSS調整は当然、
.sample_text { color: black; } となります。

それでは次に、クリックされると 【 active 】 というclassが付与されるとしましょう。
この時、以下のCSSを用意しておくと、要素にactiveというclassが付与されたら文字色を黒色から赤色に変えることができます。

.sample_text.active { color: red; }

そして元の黒色の文字色に戻したければ、activeというclassを外せば良いということになります。

ハンバーガーメニューの実装もこの『classの追加と削除』を利用します。

画面左端のさらに左奥に隠してあるナビゲーションが現れるCSS、ハンバーガーボタンの画像が切り替わるCSS調整を用意しておき、あとはJavaScriptでクリックイベントが検知された時にclassの追加・削除を行うように指定するだけです。

JavaScriptプログラム解説の前に、まずは完成版のコードを確認してみましょう▼

HTML※スクロールできます

<body>
	<div class="content_body">
		<header>
			<div class="header_container">
				<div class="menu_container">
					<img class="menu_open" src="img/ham-menu-image01.png">
					<img class="menu_close" src="img/ham-menu-image02.png">    
				</div>
				<h1>サイトタイトル</h1>
			</div>
		</header>
		<nav class="sample_sp_menu">
			<ul>
				<li>HOME</li>
				<li>ABOUT</li>
				<li>NEWS</li>
				<li>CONTACT</li>
			</ul>
		</nav>
		<section>
			<div>
				<p>ここにキャッチコピーが入ります。</p>
			</div>
		</section>
	</div>
</body>

CSS※スクロールできます

.content_body {
	width: 300px;
	height: 500px;
	background: lightgrey;
	position: relative;
}
.content_body header {
	position: relative;
	background-color: black;
	color: white;
	z-index: 1;
	height: 80px;
}
.header_container {
	width: 100%;
	height: 100%;
	position: relative;
}
.header_container h1 {
	font-size: 1rem;
	width: fit-content;
	position: absolute;
	top: calc( 50% - .8rem);
	left: 0;
	right: 0;
	margin: auto;
}
.menu_container {
	width: 50px;
	height: 50px;
	position: absolute;
	top: calc(50% - 25px);
	left: 20px;
	cursor: pointer;
}
.menu_container img {
	width: 100%;
	filter: invert(1);
	position: absolute;
	top: 0;
	left: 0;
}
.menu_open {
	opacity: 1;
}
	.menu_open.active {
		opacity: 0;
	}
.menu_close {
	opacity: 0;
}
	.menu_close.active {
		opacity: 1;
	}
.content_body section {
	height: 420px;
	display: grid;
	justify-content: center;
	align-content: center;
}
.sample_sp_menu {
	background-color: rgba(0,0,0,.5);
	position: absolute;
	top: 0;
	left: -300px;
	width: 100%;
	height: 100%;
	display: grid;
	justify-content: center;
	align-content: center;
	color: white;
	text-align: center;
	transition: .5s;
}
	.sample_sp_menu.active {
		left: 0;
	}
.sample_sp_menu ul {
	padding-inline: 0;
}
.sample_sp_menu li {
	list-style: none;
	margin-top: 1.5rem;
	cursor: pointer;
}

JavaScript※見切れている場合はスクロールできます

const MenuContainer = document.querySelector('.menu_container');
const MenuOpen = document.querySelector('.menu_open');
const MenuClose = document.querySelector('.menu_close');

const SPMenu = document.querySelector('.sample_sp_menu');			
	MenuContainer.addEventListener('click', () => {
		MenuOpen.classList.toggle('active');
		MenuClose.classList.toggle('active');
		SPMenu.classList.toggle('active');
	});

コードが長くなりましたが、ポイントを解説していきます。

addEventListener(‘click’,〜)でクリックイベントが起こった時の処理を記述していますが、その中でclassList.toggle( )というのが出てきていますね。

この記述こそが、要素にclassを付与したり外したりするプログラムです。

classList.toggle( )はとても便利で、( )かっこに記述したclassが要素に含まれていなければ追加し、含まれていれば外すという処理をしてくれます。

なので上記のサンプルコードでは、ハンバーガーボタンをクリックするたびに、【 active 】というclassが付与されたり外されたりすることになります。

ちなみにですが、上記のサンプルコードをWebブラウザ画面で確認すると下のようになります。
▼動画です。(動画サイズ:143kb)

メニュー切り替えに関するCSS調整は、
・left: -300px; で隠していたナビゲーションメニューを、left: 0;で現れる
・ハンバーガーメニューボタンの切り替えは、opacity: 0; ⇔ opacity: 1; で表示が切り替わる
…という単純な仕組みになっています。

    POINT!
  1. ・クリックで要素を表示させたり切り替えたい場合は、classの付与と削除でコントロールすれば良い!
  2. ・Element.classList.toggle( )でclassの付け外しが簡単にできる!
  3. ・付け外しするclassに対応するCSS調整を記述しておくことで、ハンバーガーメニューの動きが実装可能!
– 関連記事 –

今回の動画で紹介したコード!

今回の解説動画で使用したコードを掲載しています。学習用としてご自由にコピペしてお使い下さい。(※スクロールできます)

<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>hum_menu_blg</title>
	<style>
	body {
		margin: 0;
	}
	.content_body {
		width: 300px;
		height: 500px;
		background: lightgrey;
		position: relative;
	}
	.content_body header {
		position: relative;
		background-color: black;
		color: white;
		z-index: 1;
		height: 80px;
	}
	.header_container {
		width: 100%;
		height: 100%;
		position: relative;
	}
	.header_container h1 {
		font-size: 1rem;
		width: fit-content;
		position: absolute;
		top: calc( 50% - .8rem);
		left: 0;
		right: 0;
		margin: auto;
	}
	.content_body section {
		height: 420px;
		display: grid;
		justify-content: center;
		align-content: center;
	}
	.sample_sp_menu {
		background-color: rgba(0,0,0,.5);
		position: absolute;
		top: 0;
		left: -300px;
		width: 100%;
		height: 100%;
		display: grid;
		justify-content: center;
		align-content: center;
		color: white;
		text-align: center;
		transition: .5s;
	}
		.sample_sp_menu.active {
		left: 0px;
	}
	.sample_sp_menu ul {
		padding-inline: 0;
	}
	.sample_sp_menu li {
		list-style: none;
		margin-top: 1.5rem;
		cursor: pointer;
	}
		
		.menu_bt_container {
			width: 50px;
			height: 50px;
			position: relative;
			top: calc( 50% - 25px);
			left: 10px;
			cursor: pointer;
		}
		.menu_bt_container img {
			width: 100%;
			filter: invert(1);
			position: absolute;
		}
		.menu_close {
			opacity: 1;
		}
		.menu_close.active {
			opacity: 0;
		}
		.menu_open {
			opacity: 0;
		}
		.menu_open.active {
			opacity: 1;
		}
	</style>
</head>

<body>
<div class="content_body">
	<header>
		<div class="header_container">
			<div class="menu_bt_container">
				<img src="img/ham-menu-image01.png" class="menu_close">
				<img src="img/ham-menu-image02.png" class="menu_open">
			</div>
			<h1>サイトタイトル</h1>
		</div>
	</header>
	<nav class="sample_sp_menu">
		<ul>
			<li>HOME</li>
			<li>ABOUT</li>
			<li>NEWS</li>
			<li>CONTACT</li>
		</ul>
	</nav>
	<section>
		<div>
			<p>ここにキャッチコピーが入ります。</p>
		</div>
	</section>
</div>
<script>
{
	const menuBtContainer = document.querySelector('.menu_bt_container');
	const sampleSpMenu = document.querySelector('.sample_sp_menu');
	const menuClose = document.querySelector('.menu_close');
	const menuOpen = document.querySelector('.menu_open');
	
	menuBtContainer.addEventListener('click', () => {
		sampleSpMenu.classList.toggle('active');
		menuClose.classList.toggle('active');
		menuOpen.classList.toggle('active');
	});
}
</script>
</body>
</html>

« »

カテゴリーリンク

著者について- author profile -

ROYDOプロフィール写真
Michihiro

モバイルアプリ(iOS・Android)ディベロッパー&デザイナー

これまでに、可読性の高いカラーパターンを自動で生成するアプリや、『第3火曜日』といった形式で通知をスケジュールできるアプリなどを制作。

サブでWebデザイン・フロントエンドエンジニアとしても活動しています。

📝ツール・言語:JavaScript/React Native/Kotlin/Android Studio/Swift/SwiftUI

🎓資格:基本情報技術者/ウェブデザイン技能検定3級

Twitterアイコン Instagramアイコン