中級

JavaScriptでメニューを開閉する

前回はCSSだけでメニューを開閉しました。このレッスンでは、同じメニューをJavaScriptで動かします。見た目はほとんど変わりませんが、キーボードや読み上げソフトでも使えるようになり、実際のサイトで安心して使えるメニューになります。

閉じている状態と、JavaScriptでメニューを開いた状態
見た目は前回と同じ。中のしくみが変わる

CSSだけの方法との違い

CSSだけ(前回)JavaScript(今回)
ボタンチェックボックス+labelbutton 要素
開閉の合図チェックが入っているか(:checked)クラス is-open が付いているか
切り替える人ブラウザ(チェックボックスの機能)JavaScript

CSSだけの方法では、チェックボックスのON・OFFを合図にしていました。JavaScriptでは、ボタンを押したら、ボタンとメニューに is-open というクラスを付けたり外したりします。CSSには「is-open が付いていたら開いた見た目にする」と書いておきます。

手順1:HTML

  <header class="header">
    <a class="logo" href="#">Sample Cafe</a>
    <button class="menu-toggle" id="menu-toggle" aria-controls="global-nav" aria-expanded="false">
      <span class="bar"></span>
      <span class="bar"></span>
      <span class="bar"></span>
      <span class="visually-hidden">メニュー</span>
    </button>
    <nav class="global-nav" id="global-nav">
      <ul>
        <li><a href="#">HOME</a></li>
        <li><a href="#">コンセプト</a></li>
        <li><a href="#">メニュー</a></li>
        <li><a href="#">店舗案内</a></li>
        <li><a href="#">お問い合わせ</a></li>
      </ul>
    </nav>
  </header>

前回との違いは次の3つです。

  • チェックボックスと label の代わりに、button 要素を使います。button はもともと「押すための部品」なので、キーボードでも操作でき、読み上げソフトにも「ボタン」と伝わります。
  • ボタンとメニューに id を付けます。JavaScriptから見つけるための目印です。
  • aria-controls と aria-expanded は、読み上げソフトに「このボタンはどのメニューを開くのか」「いま開いているか」を伝えるための属性です。見た目には影響しません。

三本線のボタンには文字がないので、画面には見せずに読み上げソフトにだけ伝える「メニュー」という文字を入れています(visually-hidden)。

手順2:CSS

三本線とメニューのスタイルは、前回とほとんど同じです。#menu-btn:checked ~ と書いていたところを、.is-open に置き換えます。

/* ボタンに is-open が付いたら「×」に */
.menu-toggle.is-open .bar:nth-child(1) { transform: translateY(12px) rotate(45deg); }
.menu-toggle.is-open .bar:nth-child(2) { opacity: 0; }
.menu-toggle.is-open .bar:nth-child(3) { transform: translateY(-12px) rotate(-45deg); }
.menu-toggle.is-open .bar { background: #fff; }

/* メニューに is-open が付いたら画面の中へ */
.global-nav.is-open {
  right: 0;
}

button 要素には、ブラウザが最初から枠線や背景色を付けています。border: none と background: none で消しておきましょう。CSSの全体は、サンプルページのソース(右クリック →「ページのソースを表示」)で確認できます。

手順3:JavaScript

いよいよJavaScriptです。</body> の直前に書きます。

  <script>
    const toggle = document.getElementById('menu-toggle');  // ボタン
    const nav = document.getElementById('global-nav');      // メニュー

    // ボタンを押すたびに、開く・閉じるを切り替える
    toggle.addEventListener('click', function () {
      const isOpen = toggle.classList.toggle('is-open');   // 付いていなければ付ける・付いていれば外す
      nav.classList.toggle('is-open', isOpen);             // メニューもボタンと同じ状態に
      toggle.setAttribute('aria-expanded', isOpen);        // 開いているかどうかを読み上げソフトに伝える
    });

    // メニューの中のリンクを押したら閉じる(ページ内リンク用)
    nav.querySelectorAll('a').forEach(function (link) {
      link.addEventListener('click', function () {
        toggle.classList.remove('is-open');
        nav.classList.remove('is-open');
        toggle.setAttribute('aria-expanded', false);
      });
    });
  </script>

1行ずつ読んでみましょう

コード意味
document.getElementById('menu-toggle')id が menu-toggle の要素(ボタン)を見つける
const toggle = …見つけたボタンに「toggle」という名前を付けて、あとで使えるようにする
addEventListener('click', function () { … })ボタンが押されたら、{ } の中を実行する
classList.toggle('is-open')クラス is-open が付いていなければ付け、付いていれば外す。結果(付いたら true)が返ってくる
nav.classList.toggle('is-open', isOpen)メニューにも、ボタンと同じ状態で is-open を付け外しする
setAttribute('aria-expanded', isOpen)開いているかどうか(true / false)を読み上げソフトに伝える

【ポイント】JavaScriptがするのは「クラスの付け外し」だけ
メニューが動く見た目は、すべてCSSに書いてあります。JavaScriptは「押されたらクラスを付け外しする」だけ。見た目を変えたいときはCSSを、動くきっかけを変えたいときはJavaScriptを直す、と役割が分かれているので、あとから直しやすくなります。

リンクを押したら閉じる

後半の querySelectorAll('a') の部分は、「メニューの中のリンクを押したら、メニューを閉じる」処理です。同じページの中を移動するリンク(#concept など)を押したとき、メニューが開いたままにならないようにしています。

以前の教材(jQuery)で学んだ人へ

以前の教材では、jQueryを使って次のように書いていました。

$('.toggle').click(function () {
  $(this).toggleClass('active');
  $('nav').slideToggle();
});

やっていることは今回と同じで、「押されたらクラスを付け外しする」です。いまはjQueryを読み込まなくても、素のJavaScript(バニラJavaScriptとも呼びます)で同じくらい短く書けます。新しく作るサイトでは、今回の書き方をおすすめします。

まとめ

  • ボタンには button 要素を使う。キーボードや読み上げソフトでも操作できる
  • JavaScriptは、ボタンが押されたら classList.toggle でクラスを付け外しするだけ
  • 見た目の変化は、CSSで「クラスが付いていたら」と書いておく
  • aria-expanded で、開いているかどうかを読み上げソフトに伝える

次のレッスンでは、PCの幅ではメニューを横並びにして、ハンバーガーメニューを完成させます。

最近の記事 おすすめ記事

記事一覧を表示するには、カスタム投稿「演出効果」にて、4つ以上記事を作成してください。

記事一覧を表示するには、カスタム投稿「演出効果」にて、4つ以上記事を作成してください。

演出効果
  • カテゴリーなし
TOP