初心者向け!ハンバーガーメニューの作り方入門編
簡単なハンバーガーメニューの作り方を初心者向けにまとめました。HTMLの構造や制御すべきJavaScript、基本的なCSSで制作の流れを解説しています。
更新:
環境:-
PREPARATION
想定する読者と前提条件
基本的なパソコン操作ができること。HTML及びCSS,JavaScriptの基礎程度の知識が必要です。
今回の記事は、様々な情報への入り口になるように少しずつ各情報を紹介しております。
必ずしも今回ご紹介するものが正解とは限りません。使用される用途に合わせてお読み下さい。
初版完了
START
ハンバーガーメニューとは?
メニューにアクセスするための入り口に使用される三本線のアイコンのことをハンバーガーメニューと呼んでいます。 もともとは表示領域の小さい端末で利用されていましたが、現在では様々な場面で見ることが多くなってきましたね。 今回は三本線のハンバーガーメニューの作成方法を詳しく見ていきます。
どうやって作るの?
まずは、あの三本線がどのように作られているのか調査してみましょう。 各サイトでも表示方法が異なりますので、詳しく見ていきます。
Apple
span要素で構成され、CSSで横棒を作成しています。Appeは2本線で構成されているのが特徴です。
<input type="checkbox" id="ac-gn-menustate">
<label for="ac-gn-menustate" aria-hidden="true">
<span>
<span></span><!-- 上の線 -->
</span>
<span>
<span></span><!-- 下の線 -->
</span>
</label>
Sony
img要素で画像を使用して三本線が構成されています。
<button>
<img src="/header-footer/header/images/toggle_open.png" alt="メニューを開く">
</button>
svg要素で三本線を構成しています。
<div jsname="hyP9Qc" aria-label="メインメニュー" aria-controls="UCqTdf" aria-expanded="false" aria-haspopup="true" role="button" tabindex="0" jsaction="x097hd" >
<svg style="fill:#70757a;width:24px;height:24px" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M0 0h24v24H0z" fill="none"></path><path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z"></path></svg>
</div>
Microsoft
CSSの疑似要素を使用し、アイコンフォントで三本線を構成しています。
<button type="button" aria-label="すべての Microsoft を展開して、マイクロソフト製品とサービスの一覧を表示する" initialstate-label="すべての Microsoft を展開して、マイクロソフト製品とサービスの一覧を表示する" togglestate-label="Close All Microsoft list" aria-expanded="false" tabindex="2"></button>
QUESTION
まずはHTMLの構造を考えてみよう
ここから、少しずつコードを書きながらハンバーガーメニューとメニューとして機能させるためのナビゲーションバー、そしてハンバーガーメニューをタップしたい際に表示されるメニューの構成を見ていきましょう。
まずは3本線を作ろう
先程も書いたとおり、今回はインラインSVGで三本線を作成します。インラインSVGによる三本線のコードは以下のとおりです。
横幅23px 縦14px(全体で15px)でレイアウトしています。線の色やsvgのサイズは、CSSでレイアウトしていきます。
線をそれぞれ、top,middle,bottomというclassで設定しています。
また、svgのtitle要素には、ハンバーガーボタンの説明を入れるようにします。一般的にtitle要素は描画されませんが、音声支援技術などでは読み上げることができます。
<svg xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 23 15">
<title id="global-menu-title">メインメニューを開く</title>
<g><line class="top" x1="0" y1="0.5" x2="23" y2="0.5"/>
<line class="middle" x1="0" y1="7.5" x2="23" y2="7.5"/>
<line class="bottom" x1="0" y1="14.5" x2="23" y2="14.5"/></g>
</svg>
SVGハンバーガー(1)
プレビュー
ボタンとして機能させよう!
次にこの三本線に”メニューを開く”という役割を与えます。ハンバーガーメニューの目的は、隠されたサブメニューを開くというものです。 一般的にユーザーと対話するインタラクティブ要素であるbutton要素は、フォームの送信、ダイアログやメニューのオープン、アクションのキャンセル、新しいレコードの挿入や情報の表示などのアクションを実行するために使用するウィジェットです。 ここでは、メニューを開くという目的のためにボタン要素を使用してハンバーガーメニューを作成していきます。
<button type="button">
<svg xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 23 15">
<title id="global-menu-title">メインメニューを開く</title>
<g><line class="top" x1="0" y1="0.5" x2="23" y2="0.5"/>
<line class="middle" x1="0" y1="7.5" x2="23" y2="7.5"/>
<line class="bottom" x1="0" y1="14.5" x2="23" y2="14.5"/></g>
</svg>
</button>
次にボタン要素をタップ(クリック)可能な要素として配置するため、今回は49px × 49pxの大きさでボタン要素を作成し、 下記CSSを用いて、一般的なブラウザで表示されるボタンレイアウトをリセットします。
/* ボタンデザインのリセット */
button {margin:0; padding:0; border-radius:0;background:transparent; border:none;outline:none; appearance:none; }
SVGハンバーガー(2)
プレビュー
ナビゲーションメニューに組み込もう
HTMLのnav要素は、現在のページから別のページへのナビゲーションリンクを提供するために使用されます。ナビゲーションの各項目はul要素で作成されます。
先程作成したボタン要素をナビゲーションの一部として組み込んでみましょう。(少しずつコードが増えていきますので、じっくり見て下さい。)
また、レイアウトしやすいように各要素にclass名、id名を設定しています。
<nav id="global-menu">
<ul class="mobile" id="mobile-menubar" >
<li>
<button type="button" id="global-menu-button">
<svg
id="global-menu-img"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 23 15">
<g><line class="top" x1="0" y1="0.5" x2="23" y2="0.5"/>
<line class="middle" x1="0" y1="7.5" x2="23" y2="7.5"/>
<line class="bottom" x1="0" y1="14.5" x2="23" y2="14.5"/></g>
</svg>
</button>
</li>
<li class="logo" ><a href="#">タイトル</a></li>
</ul>
</nav>
オーバーレイメニューを作ろう
次に、ハンバーガーメニューをタップした際に表示するメニューを作成します。 やることは、単純でナビゲーション内にハンバーガーメニューをタップした際に表示したい内容(サブメニュー)を追加していきます。
<nav id="global-menu">
<ul class="mobile" id="mobile-menubar" >
<li>
<button type="button" id="global-menu-button">
<svg
id="global-menu-img"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 23 15">
<g><line class="top" x1="0" y1="0.5" x2="23" y2="0.5"/>
<line class="middle" x1="0" y1="7.5" x2="23" y2="7.5"/>
<line class="bottom" x1="0" y1="14.5" x2="23" y2="14.5"/></g>
</svg>
</button>
</li>
<li class="logo" ><a href="#">タイトル</a></li>
</ul>
<!-- ハンバーガーメニューをタップした場合に表示する内容 -->
<div id="global-menu-overlay" >
<ul>
<li class="link"><a href="#">SP MENU1</a></li>
<li class="link"><a href="#">SP MENU2</a></li>
<li class="link"><a href="#">SP MENU3</a></li>
</ul>
</div>
</nav>
デスクトップメニューを作ろう
パソコン画面で閲覧した場合と、スマートフォン等で閲覧した場合のナビゲーションメニューの切り替えを行う場合、 デスクトップ用のメニューを追加する必要があります。nav要素内にPC向けメニューを記載したul要素をさらに追加します。 (共通のメニューを使用する場合には不要です。)
<nav id="global-menu">
<!-- PC向けメニュー -->
<ul class="desktop" id="desktop-menubar">
<li class="logo"><a href="#">タイトル</a></li>
<li class="link"><a href="#">PC MENU1</a></li>
<li class="link"><a href="#">PC MENU2</a></li>
<li class="link"><a href="#">PC MENU3</a></li>
</ul>
<!-- SP向けメニュー -->
<ul class="mobile" id="mobile-menubar" >
<li>
<button type="button" id="global-menu-button">
<svg
id="global-menu-img"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 23 15">
<g><line class="top" x1="0" y1="0.5" x2="23" y2="0.5"/>
<line class="middle" x1="0" y1="7.5" x2="23" y2="7.5"/>
<line class="bottom" x1="0" y1="14.5" x2="23" y2="14.5"/></g>
</svg>
</button>
</li>
<li class="logo" ><a href="#">タイトル</a></li>
</ul>
<!-- ハンバーガーメニューをタップした場合に表示する内容 -->
<div id="global-menu-overlay" >
<ul>
<li class="link"><a href="#">SP MENU1</a></li>
<li class="link"><a href="#">SP MENU2</a></li>
<li class="link"><a href="#">SP MENU3</a></li>
</ul>
</div>
</nav>
WAI-ARIAを取り入れよう
と、その前にウェブアクセシビリティと言う言葉について理解する必要があります。 ウェブアクセシビリティとは、ウェブサイトの情報や機能の利用しやすさを意味します。
健常者も身体的ハンディキャップを持った人も、 パソコンやモバイル端末等様々な環境の人にも利用しやすくすることです。
WAI-ARIA(Accessible Rich Internet Applications)とは、 ブラウザや支援技術が認識できるさらなる意味をHTMLに追加することによって閲覧のしやすさを向上させ、ウェブサイト利用者の理解を助ける為の技術となります。
アクセシビリティについて詳しく知りたい場合は、下記サイトをご覧ください。
WAI-ARIAを使ってみよう
WAI-ARIAの基本は、HTML要素に適用できる追加の意味を定義しています。
この仕様では、主に次の3つの機能があります。 ロール(Role)属性は意味を、プロパティ(Property)属性は性質を、 ステート(State)属性は状態を定義しています。
これらを使いHTMLに意味付けを行うことができます。
W3Cでは、WAI-ARIAの実装例をWAI-ARIA Authoring Practices 1.1で 公開しております。今回は、メニューボタンの項目について取り上げます。
ロール、プロパティ、状態
早速ナビゲーションで利用されるWAI-ARIAの各項目を詳しく見ていきましょう。
メニューボタン関連(ハンバーガーメニュー)
- aria-haspopup="true"
-
[対象:button要素]ボタン要素が他のメニューを開くことを表します。 aria-haspopupの状態は、trueまたはmenuが最適です。他の値としては、"false"、"listbox"、"tree"、"grid"、"dialog"があります。
- aria-controls="IDREF"
-
[対象:button要素]メニュー ボタンによって制御されるメニュー要素(サブメニュー)を参照(id名を指定)します。 今回の場合、aria-controls="global-menu-overlay"と指定します。
- aria-expanded="true"
-
[対象:button要素]メニュー ボタンによって制御されるメニュー要素が展開しているのか、折りたたまれているかを表します。
true:展開中の状態
false:折りたたまれている状態
- aria-labelledby="IDREF"
-
[対象:svg要素]音声読み上げ等の支援技術を利用するユーザーがハンバーガーメニューの目的を理解することを手助けします。
メニューバー関連(永続的に見えるメニュー)
- role="menubar"
-
[対象:ul要素]視覚的に永続的なメニューは、メニューバーとして定義します。
- aria-label="string"
-
[対象:ul要素]音声読み上げ等の支援技術を利用するユーザーがメニューバーの目的を理解することを手助けします。
- role="menuitem"
-
[対象:a要素]メニューバーの項目として定義します。
- aria-current="page"
-
[対象:a要素]現在のページのURL同じURLのリンクを持つ要素に定義します。
- aria-haspopup="true"
-
[対象:a要素]メニュー項目にサブメニューが含まれているかどうかを表します。
true:サブメニュー有り
false:サブメニュー無し
- role="none"
-
[対象:li要素]要素の暗黙のロールを削除します。
隠されたメニュー
- aria-hidden="true"
-
[対象:div要素]視覚的・聴覚的に隠された要素を表します。
- role="menu"
-
[対象:ul要素]永続的ではないメニューは、メニューとして定義します。
- role="menuitem"
-
[対象:a要素]メニューの項目として定義します。
WAI-ARIAの実装
では、早速先ほど説明したWAI-ARIAを用いて、ナビゲーションメニューにWAI-ARIAを取り入れてみましょう。
<nav id="global-menu" aria-label="グローバル">
<!-- PC向けメニュー -->
<ul role="menubar" class="desktop" id="desktop-menubar" aria-label="メインナビゲーション">
<li role="none" class="logo"><a role="menuitem" href="#">タイトル</a></li>
<li role="none" class="link"><a role="menuitem" href="#">PC MENU1</a></li>
<li role="none" class="link"><a role="menuitem" href="#">PC MENU2</a></li>
<li role="none" class="link"><a role="menuitem" href="#">PC MENU3</a></li>
</ul>
<!-- SP向けメニュー -->
<ul role="menubar" class="mobile" id="mobile-menubar" aria-label="メインナビゲーション">
<li role="none">
<button
id="global-menu-button"
type="button"
aria-expanded="false"
aria-controls="global-menu-overlay"
data-close-label="メインメニューを閉じる"
data-open-label="メインメニューを開く"
aria-haspopup="true"
>
<svg
role="img"
id="global-menu-img"
aria-labelledby="global-menu-title"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 23 15">
<title id="global-menu-title">メインメニューを開く</title>
<g><line class="top" x1="0" y1="0.5" x2="23" y2="0.5"/>
<line class="middle" x1="0" y1="7.5" x2="23" y2="7.5"/>
<line class="bottom" x1="0" y1="14.5" x2="23" y2="14.5"/></g>
</svg>
</button>
</li>
<li role="none" class="logo" ><a role="menuitem" href="#">タイトル</a></li>
</ul>
<!-- ハンバーガーメニューをタップした場合に表示する内容 -->
<div id="global-menu-overlay" aria-hidden="true" aria-labelledby="global-menu-title">
<ul role="menu">
<li role="none" class="link"><a role="menuitem" href="#">SP MENU1</a></li>
<li role="none" class="link"><a role="menuitem" href="#">SP MENU2</a></li>
<li role="none" class="link"><a role="menuitem" href="#">SP MENU3</a></li>
</ul>
</div>
</nav>
ハンバーガーメニューを制御しよう
ここまで出来れば後は簡単ですね。ハンバーガーボタンがタップされた場合に、aria-expandedやaria-hidden等の属性の値を変更するJavaScriptを追加します。 ボタンが押された場合に、svgのタイトルも"メインメニューを開く"から"メインメニューを閉じる"に変更するようにしています。 また、オーバーレイメニューが表示された場合、body要素にclipというclass名を追加しています。
{
const globalMenuButton = document.querySelector('#global-menu-button');
const globalMenuImg = document.querySelector('#global-menu-img');
const body = document.querySelector('body');
let openLabel = globalMenuButton.dataset.openLabel;
let closeLabel = globalMenuButton.dataset.closeLabel;
let overlayMenu = document.querySelector(`#${globalMenuButton.getAttribute('aria-controls')}`);
let menuTitle = document.querySelector(`#${globalMenuImg.getAttribute('aria-labelledby')}`);
const toggleRegion = () => {
if (globalMenuButton.getAttribute('aria-expanded') == 'false') {
globalMenuButton.setAttribute('aria-expanded', 'true');
overlayMenu.setAttribute('aria-hidden', 'false');
menuTitle.innerHTML = closeLabel;
globalMenuButton.focus();
body.classList.add('clip');
} else {
globalMenuButton.setAttribute('aria-expanded', 'false');
overlayMenu.setAttribute('aria-hidden', 'true');
menuTitle.innerHTML = openLabel;
body.classList.remove('clip');
}
};
globalMenuButton.addEventListener('click', toggleRegion);
}
QUESTION
CSSで表示を制御してみよう!
さて、長い長いHTMLとJavaScriptの作成が終わってようやく見た目を作るときがやってきました。ここでも少しずつCSSを追加しながら ハンバーガーメニューの装飾をしていきましょう。(とは言っても、このコンテンツでの目標はすでに達成しているので、最低限のレイアウトしかこの記事では行いません。)
画面サイズ合わせて表示切り替え
まず取り掛からなくてはならないことは、表示画面幅によって表示するメニューを切り替えることです。 モバイルファーストでレイアウトを行い、デスクトップ系レイアウトはブレイクポイント側で実施します。
/* リセット系 ****************************************************************/
nav#global-menu ul { margin:0; padding:0; list-style:none; }
nav#global-menu #global-menu-button { margin:0; padding:0; border-radius:0; background:transparent; border:none;outline:none; appearance:none; }
/* モバイルレイアウト系 ******************************************************/
/* ハンバーガーメニュー系*****************************************************/
nav#global-menu ul.mobile #global-menu-button { width:49px; height:49px; cursor:pointer; }
nav#global-menu ul.mobile #global-menu-button svg { width:23px; height:15px; }
nav#global-menu ul.mobile #global-menu-button svg line { stroke:#333; }
nav#global-menu ul.mobile #global-menu-button { display:inline-flex; align-items:center; justify-content:center; }
/* オーバーレイメニュー系 ****************************************************/
nav#global-menu #global-menu-overlay { width:100%; height:100vh; visibility:hidden; overflow:hidden; }
nav#global-menu #global-menu-overlay[aria-hidden="false"] { visibility:visible; overflow:auto;}
/* PC環境の調整 *************************************************************/
nav#global-menu ul.desktop { display:none; } /* PCメニュー非表示 */
/* レイヤー管理 *************************************************************/
nav#global-menu #mobile-menubar { position:relative; z-index:110; } /* 上 */
nav#global-menu #global-menu-overlay { position:absolute; z-index:100; } /* 下 */
/* 以下モニタサイズごとの調整 ************************************************/
@media (min-width: 576px) {
}
@media (min-width: 768px) {
nav#global-menu ul.mobile { display:none; } /* SPメニュー非表示 */
nav#global-menu #global-menu-overlay{ display:none; } /* SPメニュー非表示 */
nav#global-menu ul.desktop { display:block; } /* PCメニュー表示 */
}
@media (min-width: 992px) {
}
@media (min-width: 1200px) {
}
ハンバーガーメニューを上部に固定
ここから少しずつ装飾してみましょう。まずはハンバーガーメニューをページ上部に固定し、スクロールしても常に表示されるように変更します。 ページ内に固定するためには、position:fixedを利用することで簡単に実現できます。また、メニュー高をハンバーガーメニューサイズと同じ49pxで作成するため、bodyにメニュー分のマージンを追加していきます。
/* bodyにメニュー高さ分のマージンを追加 */
body{margin:0; margin-top:49px;}
/* メニュー部に背景色を追加及びモバイルメニューをdisplay:flexを用いて横並びに変更 */
nav#global-menu ul.mobile { display:flex; width:100%; background:#E66EB2; }
/* ハンバーガーメニューを上部に固定 */
nav#global-menu { position:fixed; top:0; left:0; width:100%; }
/* PC版場合のグローバルメニューの上部固定を解除 */
@media (min-width: 768px) {
nav#global-menu { position:static; width:auto; height:auto; background:transparent; }
body{margin:0;}
}
ページ下部に固定する場合には、topをbottomに変更すれば可能です。
/* ハンバーガーメニューを上部に固定 */
nav#global-menu { position:fixed; bottom:0; left:0; width:100%; }
ハンバーガーメニューを×マークに変更
ハンバーガーメニューがタップされ、隠されたメニューが表示された際に、形を×マークに変更するようにしてみましょう。 やることは単純で、上下のバーを45度回転させ、中央のバーをopacity:0として非表示にさせています。
/* 追加コード:svg アニメーション */
nav#global-menu ul.mobile #global-menu-button svg line { transition: all 0.2s ease; }
nav#global-menu #global-menu-button line.top { transform-origin: 11.5px 0.5px; }
nav#global-menu #global-menu-button line.bottom { transform-origin: 11.5px 14.5px; }
nav#global-menu #global-menu-button[aria-expanded="true"] line.top { transform:translate(0px, 7px) rotate(45deg); }
nav#global-menu #global-menu-button[aria-expanded="true"] line.bottom { transform:translate(0px,-7px) rotate(-45deg); }
nav#global-menu #global-menu-button[aria-expanded="true"] line.middle { transform:translate(-20px, 0px); opacity: 0; }
サブメニューをアニメーション
次に隠されたサブメニューの表示をアニメーションさせてみましょう。 translateXを変更すると様々な方向からサブメニューを出現させることができます。
/* オーバーレイメニュー アニメーション系 左から右Ver */
nav#global-menu #global-menu-overlay > ul { padding-top:40px; padding-left:20px; padding-right:20px; }
nav#global-menu #global-menu-overlay { background:#eb8ec4 ; transform: translateX(-120vw); transition: all 0.2s ease-out; }
nav#global-menu #global-menu-overlay[aria-hidden="false"] { transform: translateX(0); }
/* オーバーレイメニュー アニメーション系 上から下Ver */
nav#global-menu #global-menu-overlay > ul { padding-top:40px; padding-left:20px; padding-right:20px; }
nav#global-menu #global-menu-overlay { background:#eb8ec4 ; transform: translateY(-120vh); transition: all 0.2s ease-out; }
nav#global-menu #global-menu-overlay[aria-hidden="false"] { transform: translateY(0); }
bodyスクロールの抑制
個人的に気になるサブメニュー表示時にbodyまでスクロールが影響してしまうことを抑制しましょう。 これは、行っても行わなくてもどちらでも構いません。
/* サブメニュー表示時のbodyスクロールの抑制 */
body.clip { overflow:hidden; }
フォーカス時のハイライト表示
キーボードのタブキーなどでハンバーガーメニューを操作を行う場合、視覚的にわかりやすく表示してみましょう。
/* フォーカス/ホバー時のハイライト表示 */
nav#global-menu ul.mobile #global-menu-button:focus,
nav#global-menu ul.mobile #global-menu-button:hover { outline:1px dotted #fff; background:rgba(0,0,0,.1); }
キーボード操作の優先順位の変更
タブキーを操作した場合、ハンバーガーメニュー→サイトタイトルと移動してしまいます。これをサイトタイトル→ハンバーガーに移動するように移動順序を変更しましょう。 また、この変更により、ハンバーガーメニューを開いた場合に、すぐに隠されたメニューにタブで移動することができます。 これには、htmlのtabindexを用いて順序を変更します。
<!-- SP向けメニュー -->
<ul role="menubar" class="mobile" id="mobile-menubar" aria-label="メインナビゲーション">
<li role="none">
<button tabindex="2" type="button" id="global-menu-button" aria-expanded="false" aria-controls="global-menu-overlay"
data-close-label="メインメニューを閉じる" data-open-label="メインメニューを開く" aria-haspopup="true">
<svg role="img" id="global-menu-img" aria-labelledby="global-menu-title"
xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="0 0 23 15">
<title id="global-menu-title">メインメニューを開く</title>
<g><line class="top" x1="0" y1="0.5" x2="23" y2="0.5" />
<line class="middle" x1="0" y1="7.5" x2="23" y2="7.5" />
<line class="bottom" x1="0" y1="14.5" x2="23" y2="14.5" /></g>
</svg>
</button>
</li>
<li role="none" class="logo"><a tabindex="1" role="menuitem" href="">タイトル</a></li>
</ul>
完成形
では、最終的に完成したコードを見てみましょう。結構スッキリまとまった感じですね。 もちろん、最低限のハンバーガーメニューの機能を盛り込んだ構成になっていますので、カスタマイズは必ず必要です。
HTML
<nav id="global-menu" aria-label="グローバル">
<!-- PC向けメニュー -->
<ul role="menubar" class="desktop" id="desktop-menubar" aria-label="メインナビゲーション">
<li role="none" class="logo"><a role="menuitem" href="#">タイトル</a></li>
<li role="none" class="link"><a role="menuitem" href="#">PC MENU1</a></li>
<li role="none" class="link"><a role="menuitem" href="#">PC MENU2</a></li>
<li role="none" class="link"><a role="menuitem" href="#">PC MENU3</a></li>
</ul>
<!-- SP向けメニュー -->
<ul role="menubar" class="mobile" id="mobile-menubar" aria-label="メインナビゲーション">
<li role="none">
<button
tabindex="2"
type="button"
id="global-menu-button"
aria-expanded="false"
aria-controls="global-menu-overlay"
data-close-label="メインメニューを閉じる"
data-open-label="メインメニューを開く"
aria-haspopup="true"
>
<svg
role="img"
id="global-menu-img"
aria-labelledby="global-menu-title"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 23 15">
<title id="global-menu-title">メインメニューを開く</title>
<g><line class="top" x1="0" y1="0.5" x2="23" y2="0.5"/>
<line class="middle" x1="0" y1="7.5" x2="23" y2="7.5"/>
<line class="bottom" x1="0" y1="14.5" x2="23" y2="14.5"/></g>
</svg>
</button>
</li>
<li role="none" class="logo" ><a tabindex="1" role="menuitem" href="#">タイトル</a></li>
</ul>
<!-- ハンバーガーメニューをタップした場合に表示する内容 -->
<div id="global-menu-overlay" aria-hidden="true" aria-labelledby="global-menu-title">
<ul role="menu">
<li role="none" class="link"><a role="menuitem" href="#">SP MENU1</a></li>
<li role="none" class="link"><a role="menuitem" href="#">SP MENU2</a></li>
<li role="none" class="link"><a role="menuitem" href="#">SP MENU3</a></li>
</ul>
</div>
</nav>
JavaScript
{
const globalMenuButton = document.querySelector('#global-menu-button');
const globalMenuImg = document.querySelector('#global-menu-img');
const body = document.querySelector('body');
let openLabel = globalMenuButton.dataset.openLabel;
let closeLabel = globalMenuButton.dataset.closeLabel;
let overlayMenu = document.querySelector(`#${globalMenuButton.getAttribute('aria-controls')}`);
let menuTitle = document.querySelector(`#${globalMenuImg.getAttribute('aria-labelledby')}`);
const toggleRegion = () => {
if (globalMenuButton.getAttribute('aria-expanded') == 'false') {
globalMenuButton.setAttribute('aria-expanded', 'true');
overlayMenu.setAttribute('aria-hidden', 'false');
menuTitle.innerHTML = closeLabel;
globalMenuButton.focus();
body.classList.add('clip');
} else {
globalMenuButton.setAttribute('aria-expanded', 'false');
overlayMenu.setAttribute('aria-hidden', 'true');
menuTitle.innerHTML = openLabel;
body.classList.remove('clip');
}
};
globalMenuButton.addEventListener('click', toggleRegion);
}
CSS
/* リセット系 ***************************************************************/
nav#global-menu ul { margin:0; padding:0; list-style:none; }
nav#global-menu #global-menu-button {margin:0; padding:0; border-radius:0; background:transparent; border:none; outline:none; appearance:none; }
/* モバイルレイアウト系 ******************************************************/
nav#global-menu ul.mobile { display:flex; width:100%; background:#E66EB2; }
body { margin:0; margin-top:49px; }
/* ハンバーガーメニュー系 ****************************************************/
nav#global-menu ul.mobile #global-menu-button { width:49px; height:49px; cursor:pointer; }
nav#global-menu ul.mobile #global-menu-button svg { width:23px; height:15px; }
nav#global-menu ul.mobile #global-menu-button svg line { stroke:#fff; }
nav#global-menu ul.mobile #global-menu-button { display:inline-flex;align-items:center; justify-content: center;}
/* オーバーレイメニュー系 ****************************************************/
nav#global-menu #global-menu-overlay { width:100%; height:100vh; visibility: hidden; overflow:hidden; }
nav#global-menu #global-menu-overlay[aria-hidden="false"] { visibility:visible; overflow:auto; }
nav#global-menu #global-menu-overlay > ul { padding-top:40px; padding-left:20px; padding-right:20px; }
/* オーバーレイメニュー アニメーション系 **************************************/
nav#global-menu #global-menu-overlay { background:#eb8ec4; transform:translateX(-120vw); transition:all .2s ease-out; }
nav#global-menu #global-menu-overlay[aria-hidden="false"] { transform:translateX(0); }
/* svg アニメーション系 *****************************************************/
nav#global-menu ul.mobile #global-menu-button svg line { transition:all 0.2s ease; }
nav#global-menu #global-menu-button line.top { transform-origin:11.5px 0.5px; }
nav#global-menu #global-menu-button line.bottom { transform-origin:11.5px 14.5px; }
nav#global-menu #global-menu-button[aria-expanded="true"] line.top { transform:translate(0px, 7px) rotate(45deg); }
nav#global-menu #global-menu-button[aria-expanded="true"] line.bottom { transform:translate(0px,-7px) rotate(-45deg); }
nav#global-menu #global-menu-button[aria-expanded="true"] line.middle { transform:translate(-20px, 0px); opacity:0; }
/* ハンバーガーメニューを上部に固定 ********************************************/
nav#global-menu { position:fixed; top:0; left:0; width:100%; }
/* サブメニュー表示時のbodyスクロールの抑制 ************************************/
body.clip { overflow:hidden; }
/* フォーカスホバー時のハイライト表示 ******************************************/
nav#global-menu ul.mobile #global-menu-button:focus,
nav#global-menu ul.mobile #global-menu-button:hover { outline:1px dotted #fff; background:rgba(0,0,0,.1); }
/* PC環境の調整 *************************************************************/
nav#global-menu ul.desktop { display:none; } /* PCメニュー非表示 */
/* レイヤー管理 *************************************************************/
nav#global-menu #mobile-menubar { position:relative; z-index:110; } /* 上 */
nav#global-menu #global-menu-overlay { position:absolute; z-index:100; } /* 下 */
/* 以下モニタサイズごとの調整 ************************************************/
@media (min-width: 576px) {
}
@media (min-width: 768px) {
nav#global-menu ul.mobile { display:none; } /* SPメニュー非表示 */
nav#global-menu #global-menu-overlay{ display:none; } /* SPメニュー非表示 */
nav#global-menu ul.desktop { display:block; } /* PCメニュー表示 */
/* ハンバーガーメニューを上部に固定解除 */
nav#global-menu { position:static; height:auto; width:auto; background:transparent; }
body { margin:0; }
}
@media (min-width: 992px) {
}
@media (min-width: 1200px) {
}
QUESTION
おまけ、CSSだけで動くように
念の為、JSがOFFの場合にCSSだけで動くように変更してみましょう。 CSSでハンバーガーメニューを動かす手段としては、チェックボックスを利用した表示のON・OFFが挙げられます。 代表的にな実装例としては、Appleのサイトで採用されています。
HTMLにinput要素を追加
global-menuの直下にinput要素を追加し、JavaScriptが有効な場合には非表示に設定します。
<!-- JavaScriptが無効な場合にも、CSSだけで動くように -->
<input class="mobile" id="mobile-menu-state" type="checkbox" name="checkbox-mobile-menu-state">
<script>
{ document.querySelector('#mobile-menu-state').style.display ='none'; }</script>
CSSにチェックボックスがONの場合の動作追加
チェックボックスが有効な場合に、svgとオーバーレイメニューが動作するように調整をします。
/* CSSだけで動くように調整 **************************************************/
nav#global-menu input#mobile-menu-state { position:absolute; left:0; top:0; width:49px; height:49px; }
nav#global-menu input#mobile-menu-state { z-index: 120; appearance:none; margin:0; padding:0; border:none; background:none; }
nav#global-menu input#mobile-menu-state:hover,
nav#global-menu input#mobile-menu-state:focus{ border:1px dotted #fff; background:rgba(0,0,0,.1);}
nav#global-menu input#mobile-menu-state:checked ~ ul#mobile-menubar line.top { transform:translate(0px, 7px) rotate(45deg); }
nav#global-menu input#mobile-menu-state:checked ~ ul#mobile-menubar line.bottom { transform:translate(0px,-7px) rotate(-45deg); }
nav#global-menu input#mobile-menu-state:checked ~ ul#mobile-menubar line.middle { transform:translate(-20px, 0px); opacity:0; }
nav#global-menu input#mobile-menu-state:checked ~ div#global-menu-overlay { transform: translateX(0); visibility:visible; overflow:auto;}
@media (min-width: 768px) {
nav#global-menu input#mobile-menu-state { display:none; } /* SPメニュー非表示 */
}
COMPLETE
SKILL
習得スキルボード
- ハンバーガーメニューの作り方
- メディアクエリーの初歩
- WAI-ARIA基礎