ハンバーガーメニューの実装方法

主にモバイル端末においてナビゲーションメニューを呼び出すために使われるハンバーガーメニューですが、皆さんはどのように実装していますか?
jQuery(JS)を使ったりHTMLとCSSだけで作ったりする人もいるでしょう。私はjQueryを使いつつHTMLとCSSの機能をできるだけ活かして実装しています。
メニューの開閉を判別するために、専用のクラスを付け外ししたりチェックボックスと連動させたりする方法がよく使われますが、個人的にはどちらの方法もあまり好きではありません。
前者ではスタイルに使わないクラスを記述する必要があるからです。そもそもCSSのクラスは共通するスタイルをまとめるために使うのが基本的だと思います。それなのに判別のためだけに中身の無いクラスをフラグとして用いるのは、本来の使い方から逸脱しているように思えます。
後者では単純に記述量が増えるからです。JSを使わない分どのブラウザでも動く安心感はありますが、非表示のチェックボックスが必要なのに加えて要素の前後関係に制約があります。さらにメニューを開くためのボタンをbutton要素ではなくlabel要素で表現するなど、HTML、CSSともに全体的に複雑で分かりにくくなります。複数のメニューを作る場合はなおさらです。
そこで私はHTML内でフラグを定義し、JSでその値の切り替えを行なってCSSで要素を動かすという方法を採っています。なんだかややこしいですがコードを見ながら理解しましょう。
わたし流ハンバーガーメニューの実装方法
この方法はHTMLのARIA属性を使うのが特徴です。すでに同じ方法で実装している人もいるようですが、あくまでも自分で思いついたので「わたし流」としています。なお、当ブログにおいても同じ方法で実装しています。
HTML
主要な記述はたったこれだけです。実際には各自でメニューの中身を作ってもらう必要があります。
<button id="humberger" aria-controls="menu" aria-expanded="false"></button>
<nav id="menu" aria-hidden="true">
button要素はいわゆるハンバーガーメニューで、nav要素は開閉される中身となります。button要素のaria-expanded属性がフラグに当たります。初期値は「false」となっていて閉じさせている状態を示し、切り替わると「true」となって開かせている状態を示すようになります。
aria-controls属性にはそのボタンで開閉する要素をIDで指定します。実際に開閉されるnav要素のid属性と一致しているのが分かります。
aria-hidden属性は開閉の状態を示します。「true」は閉じた状態を、「false」は開いた状態を示します。
このようにHTMLにおいては少ない記述で、なおかつ開閉の状態が一目で分かります。
CSS
CSSでは記述が長くなってしまうのでSassのコードを記載します。
#humbergerそのものはハンバーガーメニューの真ん中の線を表し、擬似要素で上下の線を表しています。位置やサイズの指定は適宜変更してください。
#humberger {
position: fixed;
top: 7vw;
right: 3vw;
width: 5vw;
height: 0.8vw;
outline: none;
background-color: black;
&:before, &:after {
content: "";
position: absolute;
display: block;
width: inherit;
height: inherit;
visibility: visible;
background-color: inherit;
transition: .5s;
}
&[aria-expanded="true"] {
$degree: 45deg;
visibility: hidden;
&:before {
top: 0;
transform: rotate(-$degree);
}
&:after {
bottom: 0;
transform: rotate($degree);
}
}
&[aria-expanded=“false”] {
$space: 2vw;
&:before {
top: -$space;
}
&:after {
bottom: -$space;
}
}
}
#menu {
position: fixed;
z-index: 2;
top: 0;
bottom: 0;
right: 0;
transition: .5s;
background-color: black;
&[aria-hidden="true"] {
width: 0;
}
&[aria-hidden="false"] {
width: 50vw;
}
}
ここではARIA属性の値ごとにスタイルを分けている点に注目です。フラグの値によってどのようなスタイルが割り当てられるかが一目で分かります。プログラミングにおける条件分岐のような感覚ですね。
JavaScript
常にハンバーガーメニューに対するクリックやタップを監視しています。反応があるたびにARIA属性の値を切り替えるだけです。
$('#humberger').click(function() {
let id = '#' + $(this).attr('aria-controls');
let attr = 'aria-expanded';
let hidden = $(this).attr(attr);
let expanded = hidden === 'true' ? 'false' : 'true';
$(this).attr(attr, expanded);
$(id).attr('aria-hidden', hidden);
});
最後の2行でbutton要素とnav要素のフラグの値を切り替えています。
まとめ
フラグの名前を変更する場合には、3つのファイルを修正する必要があるので保守性が高い訳ではありません。しかし、各ファイルにおける役割が明確になり、それぞれの記述が単純になると思います。