ハンバーガーメニューを作る

メモ:  Category:css

市民権を得たのかこの先淘汰されるのか、3本線で表現されるメニューボタンのハンバーガーメニューを作成します。

さまざまな作り方があるようですが、ここでは button 要素と疑似要素を使って作成します。

完成したハンバーガーメニュー

ここで作成するハンバーガーメニューは、 HTML ・ CSS ・ JavaScript を使っています。次のコードで、ボタン部分のアニメーションやメニューの表示・非表示が行えるようになります。 nav 要素の部分がドロワーメニューになるのですが、この部分の表示非表示は含んでいません。

完成イメージ

まずは、HTML。

<body>
    <button type="button" id="hamburger-btn" class="c-hamburger" role="button" aria-expanded="false" aria-controls="drawer">
        <span class="c-hamburger__line">
        </span>
    </button>
    <nav id="drawer" aria-labelledby="hamburger-btn">
    </nav>
</body>

スタイルシート。

.c-hamburger {
  position:relative;
  width: 38px;
  height: 38px;
  border: none;
  outline: none;
  background: transparent;
  outline: none;
  -webkit-transition: all .3s ease-in-out;
          transition: all .3s ease-in-out;
}
.c-hamburger__line {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  display: block;
  margin: auto;
  width: 18px;
  height: 2px;
  background-color: #011729;
  -webkit-transition: inherit;
          transition: inherit;
}
.c-hamburger__line::before,
.c-hamburger__line::after {
  content: '';
  position: absolute;
  display: block;
  width: 100%;
  height: 100%;
  background-color: inherit;
  -webkit-transition: inherit;
          transition: inherit;
}
.c-hamburger__line::before {
  top: -5px;
}
.c-hamburger__line::after {
  top: 5px;
}
.c-hamburger[aria-expanded="true"] .c-hamburger__line {
  background-color: transparent;
}
.c-hamburger[aria-expanded="true"] .c-hamburger__line::before,
.c-hamburger[aria-expanded="true"] .c-hamburger__line::after {
  top: 0;
  background-color: #011729;
}
.c-hamburger[aria-expanded="true"] .c-hamburger__line::before {
  -webkit-transform: rotate(45deg);
      -ms-transform: rotate(45deg);
          transform: rotate(45deg);
}
.c-hamburger[aria-expanded="true"] .c-hamburger__line::after {
  -webkit-transform: rotate(-45deg);
      -ms-transform: rotate(-45deg);
          transform: rotate(-45deg);
}

jQuery を使っています。

$(function(){
  $("#hamburger-btn").on("click", function() {
    $("body").toggleClass("is-drawerActive");
    if ($(this).attr('aria-expanded') == 'false') {
      $(this).attr('aria-expanded', true);
    } else {
      $(this).attr('aria-expanded', false);
    }
  });
}) ();

3本線のボタンを作成する

正解があるのか分かりませんが、 button 要素を選択した理由の1つは「キーボードで操作できる」というところにあります。

3本線を描くだけであれば、 span 要素や div 要素を使って描くことができますが、これらの要素にはフォーカスがあたりません。 HTML の要素の中でフォーカスのあたる要素は、基本的に a 要素とフォームのコントロール要素だけになります。

以前参考にさせていただいたハンバーガーメニューは、チェックボックス( input 要素)や label 要素を使用したものでしたが、ここではキーボードでも操作できるということで button 要素を使っていきます。

完成した部品には、「 aria-expanded 」や「 aria-controls 」などの属性が付加されていますが3本線を引くだけであれば次のタグと CSS のみで作成することができます。3本線の「線」の部分は、 span 要素で描きます。

<button class="c-hamburger">
  <span class="c-hamburger__line">
  </span>
</button>

この例では、 38px のボタンを作成します。 position:relative; は、疑似要素の位置を決めるために必要になるので定義しておきます。ボタン自体は、見える必要が無いため border や outline を none に設定し枠線や影を消しておきます。

.c-hamburger {
  position:relative;
  width: 38px;
  height: 38px;
  border: none;
  outline: none;
  background: transparent;
}

次に「線」を1本引きます。幅 18px , 高さ 2px のボックスを作り背景色を設定します。 margin: auto; とすることでセンターリングされ、1本の線が描かれます。

.c-hamburger__line {
  position: absolute;
  display: block;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  margin: auto;
  width: 18px;
  height: 2px;
  background-color: #011729;
}

ハンバーガーメニューに必要な線は3本なので残りの2本は、疑似要素を before と after で用意します。疑似要素は、上下に 5px ずらすことで3本の線となるよう設定します。

.c-hamburger__line {
  position: absolute;
  display: block;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  margin: auto;
  width: 18px;
  height: 2px;
  background-color: #011729;
}
.c-hamburger__line::before,
.c-hamburger__line::after {
  content: '';
  position: absolute;
  display: block;
  width: 100%;
  height: 100%;
  background-color: inherit;
}
.c-hamburger__line::before {
  top: -5px;
}
.c-hamburger__line::after {
  top: 5px;
}

ここまでで3本線のボタンが用意できます。

ハンバーガーメニューをアニメーションさせる

ハンバーガーメニューを変形して閉じるボタンを作成します。ここでは、 aria-expanded という属性を使いますが aria-controls 属性や aria-expanded 属性は WAI-ARIA (Web Accessibility Initiative – Accessible Rich Internet Applications) というアクセシビリティを向上させるための属性になります。

最低限必要なものだけを書くと次のような HTML になりますが aria-expanded だけでは「何が expanded されているんだ?」となってしまうので、本来であれば aria-owns 属性や aria-control 属性等で展開される要素を明示する必要があります。

とりあえず、動作確認を単純化するため次のような HTML にしています。

<button id="hamburger-btn" class="c-hamburger" aria-expanded="false">
  <span class="c-hamburger__line">
  </span>
</button>

ハンバーガーメニューをクリックする都度、aria-expanded 属性を変更したいので次のような JavaScript を用意します。 id 属性 hamburger-btn のボタンがクリックされると、 aria-expanded 属性の値が true / false でトグルします。

$(function(){
  $("#hamburger-btn").on("click", function() {
    if ($(this).attr('aria-expanded') == 'false') {
      $(this).attr('aria-expanded', true);
    } else {
      $(this).attr('aria-expanded', false);
    }
  });
}) ();

aria-expanded 属性が true になった時、中央の線を透過して上下2本の線を45度回転させます。アニメーションさせるため transition に all .3s ease-in-out と設定し、aria-expanded 属性が true の時に中央の線が見えなくなるよう background-color: transparent; を指定します。疑似要素にそれぞれ45度と-45度回転するように指定することで閉じるボタンに変形します。

.c-hamburger {
  position:relative;
  width: 38px;
  height: 38px;
  border: none;
  outline: none;
  background: transparent;
  outline: none;
  -webkit-transition: all .3s ease-in-out;
          transition: all .3s ease-in-out;
}
.c-hamburger__line {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  display: block;
  margin: auto;
  width: 18px;
  height: 2px;
  background-color: #011729;
  -webkit-transition: inherit;
          transition: inherit;
}
.c-hamburger__line::before,
.c-hamburger__line::after {
  content: '';
  position: absolute;
  display: block;
  width: 100%;
  height: 100%;
  background-color: inherit;
  -webkit-transition: inherit;
          transition: inherit;
}
.c-hamburger__line::before {
  top: -5px;
}
.c-hamburger__line::after {
  top: 5px;
}
.c-hamburger[aria-expanded="true"] .c-hamburger__line {
  background-color: transparent;
}
.c-hamburger[aria-expanded="true"] .c-hamburger__line::before,
.c-hamburger[aria-expanded="true"] .c-hamburger__line::after {
  top: 0;
  background-color: #011729;
}
.c-hamburger[aria-expanded="true"] .c-hamburger__line::before {
  -webkit-transform: rotate(45deg);
      -ms-transform: rotate(45deg);
          transform: rotate(45deg);
}
.c-hamburger[aria-expanded="true"] .c-hamburger__line::after {
  -webkit-transform: rotate(-45deg);
      -ms-transform: rotate(-45deg);
          transform: rotate(-45deg);
}

メニュー等の表示

後はクリックされた時のメニューをどう表示するかですが、aria-controls 属性に指定した drawer という id の要素を閉じたり開いたりさせます。この動作のトリガーに次の JavaScript を使用して body 要素の is-drawerActive 名をトグルさせます。

クラス名 is-drawerActive の有無でメニューを開いたり閉じたりすれば完成です。

$("body").toggleClass("is-drawerActive");

bluenote by BBB