Webデザインのための備忘録

webデザインをするために学んだことをアウトプットするためのブログです。

ハンバーガーメニューの作り方(JSで要素を作ろう編)

こんにちは。 webデザイン学習中、mamenoです。

前回、ハンバーガーメニューの作り方(疑似要素で頑張ろう編)という記事で、ハンバーガーメニューが開いた時の背景を疑似要素で作るパターンについて書きました。 mameno-web.hatenablog.com

今回は疑似要素を使うのではなく、JavaScriptで背景用の空タグを生成する方法で書いていきたいと思います。

※1~3(JS編-1)までは前回とほぼ同じです。
メニュー展開時の背景のマスクについてについてだけ変更しています。

今回のゴール

今回作るものは、前回同様こちらのハンバーガーメニュー。

動きとしては、 1. 三本線(ハンバーガーメニュー)をクリック(タップ) 2. 上からメニューが出てきて、背景が暗くなり、ハンバーガーは×ボタンになる 3. ×ボタン or 暗い背景をクリック(タップ)するとメニューが閉じる となります。

See the Pen Untitled by mameno (@mameno_design) on CodePen.

この時の暗い背景を、三本線(ハンバーガーメニュー)をクリックしたときにJavaScriptspanタグを生成して作っちゃおうというお話です。

1. ハンバーガーメニューを作る(HTML編)

まずは、HTMLを記述します。

See the Pen Untitled by mameno (@mameno_design) on CodePen.

今回、ハンバーガメニューを作るにあたって大切にしたことは、2つ。

  • そもそものHTMLに空の要素は作らない
  • スマホバージョンとPCバージョンのメニューは分けない

順に説明していきます。

空の要素を作らない

三本線アイコンについて

ハンバーガーメニューのアイコンというと、HTML上にspanタグを3つ並べて作るパターンをよく見かけます。
が、できればhtml上には不要な要素は置いておきたくない。
ということで、今回はbuttonタグの中にspanタグを一つ入れそこに一本線を作り、 :before:afterで残り2本を作るという方法にしました。

<button type="button" class="c-button p-hamburger js-hamburger" aria-controls="global-nav" aria-expanded="false">
  <span class="p-hamburger__line">
          <span class="u-screenReaderText">メニューを開閉する</span> //ここはスクリーンリーダー用で画面上には表示されない
  </span>
</button>

メニュー展開時の背景のマスクについて

ハンバーガーメニューが開いた時の背景のマスクについては、ハンバーガーメニューが押されたらJS側でspanタグを入れるようにするので、厳密に空要素が全くないとは言えませんが、初めからあるということは避けるようにしました。

スマホバージョンとPCバージョンのメニューは分けない

メニューを分けると、HTML上にスマホバージョンと PCバージョンのメニューが2つ存在することになるわけです。
見た目上は出し分けているので問題ないかもしれませんが、こちらも音声読みあげソフトを使用した時には、 2回メニューが読まれるわけなので鬱陶しいかなということで、HTMLは最小限の記述でcssでなんとかしていくという方法にしました。 (今回は非常にシンプルなメニューだったということもあり)

音声読み上げ用クラスについて

ちなみに、.u-screenReaderTextクラスがついているspanは、 音声読み上げソフトを使用した際に「ここを押すとナビゲーションメニューが開閉できますよ〜」と教えるためのもので、 画面上には必要ないので、後述するcssで見えなくしておきます。

2. ハンバーガーメニューを作る(CSS編)

次はCSSです。

  1. .u-screenReaderText用に隠す記述
  2. ナビゲーションのスタイル
  3. ハンバーガーボタンのスタイル

を順番に記述します。 (767px以下でハンバーガーメニューに変わります。まだ動きません。)

See the Pen Untitled by mameno (@mameno_design) on CodePen.

ハンバーガーメニューのcssについては、いろいろな方が書かれているのでここでは割愛します。

3.ハンバーガーメニューの挙動を作る(JS編-1)

  1. CSSに、.is-active-drawerがついた時の要素について追記(CodePen CSSの下にまとめてあります)
  2. JSにて、ハンバーガーボタンに.is-active-drawerをつける(外す)処理と、aria-expandedのtrue/falseを入れ替える処理の記述(この時点ではハンバーガーボタンのみでメニューの開閉)

See the Pen Untitled by mameno (@mameno_design) on CodePen.

aria-expandedって?

要素、またはそれが制御する別のグループ化要素が現在展開されているか折りたたまれているかを示します。
W3Cリファレンス より

なくても見た目には影響しませんが、アクセシビリティ的な観点から記述した方がいいものです。多分。
クラスの付け替えだけだと、aria-expandedがfalseなのに見た目では展開している感じになってしまうのできちんと書き換える処理を加えています。

4.JavaScriptで背景を生成して制御する(JS編-2)

  1. CSSに、is-active-maskがついたspan要素について記述(先ほどのさらに下に追記)
  2. JavaScriptに、ハンバーガーボタンを押したときの背景の動きについて記述

ハンバーガーボタンを押した時の処理の中に、以下を追記します。

//マスク用spanタグの生成
 const newEl = document.createElement("span");
 newEl.classList.add("is-active-mask");

if (document.querySelector(".is-active-mask") === null) {
//is-active-maskが存在しなければ処理をする
    globalNav.appendChild(newEl).addEventListener("click", () => {
      body.classList.remove("is-active-drawer");
      hamburgerButton.setAttribute("aria-expanded", false);
    });
}

動きとしては、
ハンバーガーメニューがクリック(タップ)される→
is-active-maskというクラスがついたspanタグを生成する→
is-active-maskというクラスがあるかどうかをif文で判別し、存在しなければglobalNav(.js-globalNavクラスがついた要素)の一番最後の子要素に追加する→
そしてその要素にそのままクリックイベントを定義する
という流れになります。

以下はそのデモになります。

See the Pen Untitled by mameno (@mameno_design) on CodePen.

終わりに

いかがでしたでしょうか。
今回は、JSで要素を生成してクリックイベントを定義する方法で作ってみました。
このコードのポイントは、作った要素があるかどうかを判別するのを忘れないことでしょうか。
これをしないと、「そんな要素ないよ!!」って怒られます。

ということで、これが何かの参考になれば嬉しいです。
ご覧いただき、ありがとうございましたー