コーディング案件で非常に多い実装、ハンバーガーメニュー。
LPでは無いことも多いですが、コーポレートサイトなど複数ページの場合は、ほぼ確実にあります。
そして頻出する実装でありながら、細かいことを気にするとかなり難しいです。
そこで今回は、Micromodal.jsというJavaScriptのライブラリを使った、ハンバーガーメニューの作り方を解説していきます。
Micromodal.jsの使い方とMicromodal.jsを使ったモーダルウィンドウの作り方は、以下の記事を参照下さい。
Micromodal.jsの使い方【モーダルウィンドウを簡単に実装できるライブラリ】
続きを見る
(有料になっていたらすいません🙇♂️)
micromodal.jsを使ったハンバーガーメニューの作り方
ハンバーガーメニューの作り方は多種多様ですが、今回はシンプルな以下の6種類ご紹介します。
- 右からスライド(画面半分)
- 右からスライド(全画面)
- 上からスライド(画面半分)
- 上からスライド(全画面)
- 全画面フェード
- ハンバーガーメニュー内でスクロール
共通の機能は以下になります。
- 開くときに背景を暗くする(オーバーレイ)
- 背景(オーバーレイ)をクリックで閉じる
- 開くときに背景を固定する(スクロール不可)
- 閉じるときにページトップに移動しない
- リンクをクリックするとメニューを閉じながらスムーススクロール
- ESCボタンで閉じる
全画面ではオーバーレイはなくてもいいかも知れませんが、ゆっくりメニューを開閉するので、開き切るまで薄暗くなるように今回はそのまま設定しています。
共通のコード
まずは、基本となる共通のコードを見ていきます。
HTML
基本となるHTMLはこちらです。
<header>
<!-- ハンバーガーメニューボタン -->
<button
class="hamburger"
type="button"
id="js-buttonHamburger"
aria-expanded="false"
>
<span class="hamburger-line">
<span class="visuallyHidden">メニューを開閉する</span>
</span>
</button>
</header>
<!-- オーバーレイ -->
<div class="overlay" id="js-overlay"></div>
<!-- ハンバーガーメニュー -->
<div class="modal-container" id="modal-1" aria-hidden="true">
<div tabindex="-1" data-micromodal-close>
<div role="dialog" aria-modal="true" aria-labelledby="modal-1-title">
<div id="modal-1-content">
<ul class="menu-list">
<li class="menu-item">
<a class="menu-link" href="#anchor01">HOME</a>
</li>
<li class="menu-item">
<a class="menu-link" href="#anchor02">ABOUT</a>
</li>
<li class="menu-item">
<a class="menu-link" href="#anchor03">SHOP</a>
</li>
<li class="menu-item">
<a class="menu-link" href="#anchor04">NEWS</a>
</li>
<li class="menu-item">
<a class="menu-link" href="#anchor05">ACCESS</a>
</li>
<li class="menu-item">
<a class="menu-link" href="#anchor06">CONTACT</a>
</li>
</ul>
</div>
</div>
</div>
</div>
<!-- メインコンテンツ -->
<main>
<section class="section01" id="anchor01">
<h2 class="section-title">HOME</h2>
</section>
<section class="section02" id="anchor02">
<h2 class="section-title">ABOUT</h2>
</section>
<section class="section03" id="anchor03">
<h2 class="section-title">SHOP</h2>
</section>
<section class="section04" id="anchor04">
<h2 class="section-title">NEWS</h2>
</section>
<section class="section05" id="anchor05">
<h2 class="section-title">ACCESS</h2>
</section>
<section class="section06" id="anchor06">
<h2 class="section-title">CONTACT</h2>
</section>
</main>
オーバーレイに関しては、不要であれば削除して下さい。
CSS
共通のCSSはこちらです。
/* アクセシビリティ対策 */
.visuallyHidden {
border: 0;
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
white-space: nowrap;
width: 1px;
}
/* ハンバーガーボタンのスタイル */
.hamburger {
appearance: none;
background-color: transparent;
border: none;
cursor: pointer;
display: block;
height: 32px;
outline: none;
position: fixed;
right: 30px;
top: 30px;
transition: transform .6s, width .6s;
width: 40px;
z-index: 200; /* メニューよりも上にする */
}
/* ハンバーガーメニュー三本線 */
.hamburger-line {
background-color: #000;
height: 2px;
left: 0;
margin: auto;
position: absolute;
right: 0;
top: 0;
transition: inherit;
width: 100%;
}
.hamburger-line::before,
.hamburger-line::after {
background-color: #000;
content: "";
display: block;
height: 100%;
position: absolute;
transition: inherit;
width: 100%;
}
.hamburger-line::before {
top: 10px;
}
.hamburger-line::after {
top: 20px;
}
/* ハンバーガーメニュー三本線オープン時 */
.hamburger[aria-expanded="true"] .hamburger-line {
transform: translateY(15px) rotate(-45deg);
}
.hamburger[aria-expanded="true"] .hamburger-line::before {
transform: translateY(-12px) translateX(20px) rotate(45deg);
width: 0;
}
.hamburger[aria-expanded="true"] .hamburger-line::after {
transform: translateY(-20px) rotate(90deg);
}
/* オーバーレイのスタイル */
.overlay {
background-color: #333;
cursor: pointer;
height: 100vh;
left: 0;
opacity: 0;
position: fixed;
top: 0;
transition: opacity .6s, visibility .6s;
visibility: hidden;
width: 100vw;
z-index: 10; /* メニューよりも下にする */
}
.overlay.active {
opacity: .8;
visibility: visible;
}
/* メニューのスタイル */
.modal-container {
background-color: #fff;
position: fixed;
z-index: 20; /* オーバーレイよりも上にする */
}
.modal-container[aria-hidden="false"] {
overflow-y: scroll;
}
.menu-item {
margin-top: 20px;
text-align: center;
}
.menu-link {
display: inline-block;
}
/* セクションのスタイル */
section {
background-color: rgba(255, 255, 255, .1);
background-image: repeating-linear-gradient(45deg, transparent, transparent 10px, rgba(255, 1, 1, .1) 10px, rgba(255, 1, 1, .1) 20px );
background-size: auto auto;
height: 300px;
}
.section-title {
color: #333;
font-size: 50px;
text-align: center;
}
.section01 {
background-color: #e2ffc6;
}
.section02 {
background-color: #c6ffff;
}
.section03 {
background-color: #ffc6ff;
}
.section04 {
background-color: #ffe2c6;
}
.section05 {
background-color: #c6c6ff;
}
.section06 {
background-color: #ffffc6;
}
CSSも、オーバーレイが不要であれば削除して下さい。
CSSはこれに追記していく形で解説していきます。
注意ポイント
JavaScript
共通のJavaScriptはこちらになります。
window.addEventListener("DOMContentLoaded", () => {
// ページ内リンクの取得
const anchorLinks = document.querySelectorAll('a[href^="#"]');
// NodeList を Array に変換
const anchorLinksArr = Array.from(anchorLinks);
// ハンバーガーメニューボタンの取得
const btn = document.querySelector("#js-buttonHamburger");
// オーバーレイの取得
const overlay = document.querySelector("#js-overlay");
// ページ内リンクのクリックイベントリスナー
anchorLinksArr.forEach((link) => {
link.addEventListener("click", (e) => {
e.preventDefault(); // デフォルトの挙動をキャンセル
const targetId = link.hash; // リンク先の要素のIDを取得
const targetElement = document.querySelector(targetId); // リンク先の要素を取得
const targetoffsetTop =
window.pageYOffset + targetElement.getBoundingClientRect().top; // スクロール量を取得
// メニューが開いている場合は閉じる
if (btn.ariaExpanded == "true") {
btn.ariaExpanded = false;
overlay.classList.remove("active"); // オーバーレイを非表示にする
}
// 全てのページ内リンク要素の ariaExpanded を false にする
anchorLinksArr.forEach((link) => {
link.ariaExpanded = false;
});
MicroModal.close("modal-1"); // モーダルを閉じる
// スムーススクロール
window.scrollTo({
top: targetoffsetTop,
behavior: "smooth", // スムーススクロールを有効にする
});
});
});
// ハンバーガーメニューボタンのクリックイベントリスナー
btn.addEventListener("click", function () {
if (btn.ariaExpanded == "false") {
btn.ariaExpanded = true;
MicroModal.show("modal-1", {
disableScroll: true, // スクロールを無効化
awaitOpenAnimation: true, // 開くアニメーションの完了を待つ
});
overlay.classList.add("active"); // オーバーレイを表示する
} else {
btn.ariaExpanded = false;
MicroModal.close("modal-1", {
awaitCloseAnimation: true, // 閉じるアニメーションの完了を待つ
});
overlay.classList.remove("active"); // オーバーレイを非表示にする
}
});
// オーバーレイのクリックイベントリスナー
overlay.addEventListener("click", function () {
btn.ariaExpanded = false;
MicroModal.close("modal-1", {
awaitCloseAnimation: true, // 閉じるアニメーションの完了を待つ
});
overlay.classList.remove("active"); // オーバーレイを非表示にする
});
// ESCキーが押された時の処理
document.addEventListener("keydown", function (e) {
if (e.key === "Escape") {
btn.ariaExpanded = false;
MicroModal.close("modal-1", {
awaitCloseAnimation: true, // 閉じるアニメーションの完了を待つ
});
overlay.classList.remove("active"); // オーバーレイを非表示にする
}
});
});
JavaScriptも、オーバーレイが不要であれば削除して下さい。
それでは、これから6種類のハンバーガーメニューをご紹介していきます。
ここからご紹介するコードは、CSSの共通コードに追記するものだけ書きますが、全部見たい人はデモの左上にある『HTML / CSS / JavaScript』をクリックして下さい。
また、HTMLとJavaScriptに関しては、オーバーレイを削除するかどうか以外はノータッチです。
右からスライド(画面半分)
追記するコードはこちら。
/* メニューのスタイル */
.modal-container {
height: 100%;
right: -100%;
transition: right .6s ease-in-out;
width: 50%;
}
.modal-container[aria-hidden="false"] {
right: 0;
transition: right .6s ease-in-out;
}
これは、メニューを開く前はright: -100%;
で、右に100%移動して見えなくしています。
そしてメニューを開くと、right: 0;
で右から左に移動してきます。
そしてメニューは画面幅の半分のwidth: 50%;
となっています。
デモはこちら。
See the Pen
Untitled by junpei (@junpei-sugiyama)
on CodePen.
右からスライド(全画面)
これは、先ほどのwidth: 50%;
をwidth: 100%;
にするだけです。
/* メニューのスタイル */
.modal-container {
height: 100%;
right: -100%;
transition: right .6s ease-in-out;
width: 100%; /* 全画面にする */
}
.modal-container[aria-hidden="false"] {
right: 0;
transition: right .6s ease-in-out;
}
デモはこちら。
See the Pen
Untitled by junpei (@junpei-sugiyama)
on CodePen.
オーバーレイは有効にしてあります。
上からスライド(画面一部)
今度は、上からスライドさせます。
ここでは画面上部半分にしますが、実際はもっと短いと思います。
追記するコードはこちら。
/* メニューのスタイル */
.modal-container {
height: 50%;
top: -100%;
transition: top .6s ease-in-out;
width: 100%;
}
.modal-container[aria-hidden="false"] {
top: 0;
transition: top .6s ease-in-out;
}
右からスライドする時との違いは、以下になります。
right
→top
height: 100%;
→height: 50%;
width: 50%;
→width: 100%;
デモはこちら。
See the Pen
Untitled by junpei (@junpei-sugiyama)
on CodePen.
上からスライド(全画面)
これは、先ほどのheight: 50%
をheight: 100%
にするだけです。
/* メニューのスタイル */
.modal-container {
height: 100%;
top: -100%;
transition: top .6s ease-in-out;
width: 100%;
}
.modal-container[aria-hidden="false"] {
top: 0;
transition: top .6s ease-in-out;
}
デモはこちら。
See the Pen
Untitled by junpei (@junpei-sugiyama)
on CodePen.
全画面フェード
フェードにする場合は、以下のコードを追記します。
/* メニューのスタイル */
.modal-container {
height: 100%;
opacity: 0;
transition: opacity .6s, visibility .6s;
visibility: hidden;
width: 100%;
}
.modal-container[aria-hidden="false"] {
opacity: 1;
visibility: visible;
}
オーバーレイでも同じですが、opacity
だけだと見えないだけでメインコンテンツに重なってしまうので、visibility
を書いています。
また、display: none;
からdisplay: block;
だとtransition
が効かないので、このような書き方をしています。
transition
が不要であれば、display: none;
からdisplay: block;
でもOKです。
それぞれの違いについては、以下の記事を参照下さい。
【CSS】display: noneとopacity: 0とvisibility: hiddenの違いを解説
続きを見る
デモはこちら。
See the Pen
Untitled by junpei (@junpei-sugiyama)
on CodePen.
ハンバーガーメニュー内でスクロール
これに関しては、実はここまでの例で出来ています。
あとはメニューが縦に収まらないように長くするだけですが、このスクロールを可能にしているのは以下のコードです。
.modal-container[aria-hidden="false"] {
overflow-y: scroll;
}
y軸ではみ出た部分を、スクロール可能にしています。
デモはこちら。
See the Pen
Untitled by junpei (@junpei-sugiyama)
on CodePen.
まとめ
今回は、Micromodal.jsを使ったハンバーガーメニューの作り方を解説してきました。
ハンバーガーメニューは、背景固定やオーバーレイ、リンククリックでメニューを閉じながらページ内スクロールなど、色々やることがあります。
そして案件ごとに毎回違う実装なので結構苦戦すると思いますが、ここのデモを元にすれば、大抵の実装は可能かと思います(デザインなどの調整は当然必要です)
また、今回の記事は以下のnoteを参考にさせて頂きました。
参考:ハンバーガーメニュー(micromodal.js使用)
以上になります。