ハンバーガーメニューを作りながら、アクセシビリティのことを初めて考えた
この記事で学んだこと:classList.toggle() / BEM / aria-label
はじめに
スクールのコーディングテスト対策として、ハンバーガーメニューを実装しました。
正直、作る前は「JavaScriptでメニューを開閉するってどういうこと?」という状態でした。でも実際に手を動かして作ってみたら、classList.toggle() という便利なメソッドの存在を知り、思ったよりシンプルに実装できました。この記事では、そのときの学びをまとめます。
classList.toggle() とは?
一言でいうと、クラスの「あり・なし」を切り替えるメソッドです。
要素.classList.toggle('クラス名');
クラスがついていなければ追加、ついていれば削除してくれます。
add / remove との違い
| メソッド | 動き |
|---|---|
classList.add('open') |
クラスを追加するだけ |
classList.remove('open') |
クラスを削除するだけ |
classList.toggle('open') |
あれば消す・なければ追加する |
メニューの「開く・閉じる」は繰り返し切り替えるので、toggle を使うのがぴったりでした。
実装したコード
HTML
<!-- ハンバーガーボタン -->
<button class="header__hamburger" type="button" aria-label="メニューを開く">
<span></span>
<span></span>
<span></span>
</button>
<!-- オーバーレイメニュー -->
<div class="header__overlay">
<nav>
<ul>
<li><a href="">about</a></li>
<li><a href="">products</a></li>
<li><a href="">story</a></li>
<li><a href="">contact</a></li>
</ul>
</nav>
</div>
クラス名は BEM記法(ブロック__要素)で命名しています。
CSS
/* オーバーレイの初期状態(非表示) */
.header__overlay {
opacity: 0; /* 透明 */
pointer-events: none; /* クリックを無効化 */
transition: opacity 0.4s ease; /* フェードのアニメーション */
position: fixed;
inset: 0; /* 上下左右0 = 画面全体に広がる */
z-index: 100;
background: rgba(58, 42, 36, 0.92);
display: flex;
justify-content: center;
align-items: center;
}
/* openクラスがついたとき(表示) */
.header__overlay.open {
opacity: 1;
pointer-events: auto;
}
opacity: 0 だけだと見えないだけでクリックは効いてしまうので、pointer-events: none で操作も無効化するのがポイントです。
JavaScript
const btn = document.querySelector('.header__hamburger');
const overlay = document.querySelector('.header__overlay');
btn.addEventListener('click', () => {
btn.classList.toggle('open');
overlay.classList.toggle('open');
});
ボタンをクリックするたびに、ボタンとオーバーレイの両方に open クラスをトグルしています。
詰まったところ
div じゃなくて button を使う理由
最初、ハンバーガーボタンのHTMLを <div> で書いていました。しかし実は <button> を使うべきです。
理由はアクセシビリティのため。<button> はキーボードのEnterキーでも押せたり、スクリーンリーダーが「ボタン」として読み上げてくれます。<div> にはそういった機能がありません。
「クリックできるものは button」と覚えておくことにしました。
aria-label を知った
<button> に aria-label="メニューを開く" という属性を追加しました。
これは、スクリーンリーダー(視覚に障害がある方が使う読み上げソフト)向けに「このボタンが何をするものか」を伝えるためのものです。三本線だけのボタンは見た目ではわかっても、読み上げソフトには伝わらないので必要なんですね。
正直、最初は「なくてもいいのでは?」と思っていましたが、アクセシビリティを意識することの大切さを知るきっかけになりました。
まとめ
classList.toggle()は開閉など「切り替え」の実装にぴったりopacity: 0とpointer-events: noneはセットで使う- クリックできる要素は
<div>より<button>を使う aria-labelでスクリーンリーダーにも伝わるコードを書く