CSSだけで作るハンバーガメニュー

スマホでWEBサイトを見ると画面の右上や左上でよく見かける3本線。

ハンバーガーメニュー
ゆんつ
家紋かな?

この三本戦をタップすると、たいていの場合画面外の左や右からメニューがスライドして現れます。

ハンバーガーメニュー

これを「ハンバーガーメニュー」とか「ドロワーメニュー」とか言ったりします。

この「ハンバーガーメニュー」は「CSSとjQuery」で作ることもできますが、もっと手軽に「CSS」だけでも作ることができます。

今日はCSSだけで「ハンバーガーメニュー」を作る方法について書きたいと思います。

ハンバーガメニューの作り方

閉じるボタン有り

メニューが表示された時に、そのメニューを閉じるための×印があるバージョンです。

See the Pen hamburger1 by konpure (@yuntu) on CodePen.

三本線をクリックしていただくと、メニューを閉じるための×印にかわります。

HTML

<header class="header">
  <div class="logo">TEST</div><!-- /.logo -->

  <!-- ハンバーガーメニュー部分 -->
  <div class="drawer">

    <!-- ハンバーガーメニューの表示・非表示を切り替えるチェックボックス -->
    <input type="checkbox" id="drawer-check" class="drawer-hidden" >

    <!-- ハンバーガーアイコン -->
    <label for="drawer-check" class="drawer-open"><span></span></label>

    <!-- メニュー -->
    <nav class="drawer-content">
      <ul class="drawer-list">
        <li class="drawer-item">
          <a href="">リンク1</a>
        </li><!-- /.drawer-item -->
        <li class="drawer-item">
          <a href="">リンク2</a>
        </li><!-- /.drawer-item -->
        <li class="drawer-item">
          <a href="">リンク3</a>
        </li><!-- /.drawer-item -->
      </ul><!-- /.drawer-list -->
    </nav>

  </div>
</header>

一番大切なのは要素の並び順です。

ハンバーガーメニュー部分を作る場合にはチェックボックスが一番上にくるようにします。

これは後ほどCSSで「~」というセレクタを利用して、スタイルの設定を行うからです。

「~」というセレクタは「同じ階層にある後続の要素に対してスタイルを設定」するセレクタです。

チェックボックスへのチェックの有無は、CSSのcheckedにより監視されています。

チェックボックスにチェックが入ったことをCSSのcheckedで確認し、「~」というセレクタで後続の要素を選択してスタイルを設定することで、チェックボックスよりも後ろにある要素(メニューアイコンやメニュー)にスタイルが設定され、画面外からメニューが現れたり、メニューアイコンが三本線から×印に変化したりします。

そのためにチェックボックスが一番上にある必要があります。

CSS

.header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0 20px;
  background: #fff;
}

.logo {
  font-size: 24px;
}

/*------------------------------

  ここから下がハンバーガーメニュー
  に関するCSS

------------------------------*/
  
/* チェックボックスは非表示に */
.drawer-hidden {
  display: none;
}

/* ハンバーガーアイコンの設置スペース */
.drawer-open {
  display: flex;
  height: 60px;
  width: 60px;
  justify-content: center;
  align-items: center;
  position: relative;
  z-index: 100;/* 重なり順を一番上に */
  cursor: pointer;
}

/* ハンバーガーメニューのアイコン */
.drawer-open span,
.drawer-open span:before,
.drawer-open span:after {
  content: '';
  display: block;
  height: 3px;
  width: 25px;
  border-radius: 3px;
  background: #333;
  transition: 0.5s;
  position: absolute;
}

/* 三本線のうち一番上の棒の位置調整 */
.drawer-open span:before {
  bottom: 8px;
}

/* 三本線のうち一番下の棒の位置調整 */
.drawer-open span:after {
  top: 8px;
}

/* アイコンがクリックされたら真ん中の線を透明にする */
#drawer-check:checked ~ .drawer-open span {
  background: rgba(255, 255, 255, 0);
}

/* アイコンがクリックされたらアイコンが×印になように上下の線を回転 */
#drawer-check:checked ~ .drawer-open span::before {
  bottom: 0;
  transform: rotate(45deg);
}

#drawer-check:checked ~ .drawer-open span::after {
  top: 0;
  transform: rotate(-45deg);
}
  
/* メニューのデザイン*/
.drawer-content {
  width: 100%;
  height: 100%;
  position: fixed;
  top: 0;
  left: 100%;/* メニューを画面の外に飛ばす */
  z-index: 99;
  background: #fff;
  transition: .5s;
}

/* アイコンがクリックされたらメニューを表示 */
#drawer-check:checked ~ .drawer-content {
  left: 0;/* メニューを画面に入れる */
}

チェックボックス自体は表示しておく必要はないので非表示にしておきます。

メニューアイコンはlabel要素の中にあるspan要素と疑似要素で作っています。

メニューアイコンは常に表示させておきたいので、z-Indexを使って重なり順を一番上にしています。

このメニューアイコンがクリックされるとチェックボックスにはチェックが入ります。

CSSの:checkedによりチェックボックスへのチェックは監視されいます。

「drawer-check:checked ~」となっているようにチェックボックスにチェックが入るとチェックボックスよりも後ろにある要素にいろいろなデザインが設定されます。

具体的に言うとメニューアイコンは3本線の真ん中は消えて上下の線がクロスして×印をつくります。

そしてチェックボックスにチェックが入ったことにより「left: 100%」で画面外に飛ばしていたメニューが「left: 0」となり、画面右側からスライドしてきます。

メニューが画面内に入ってくるときの速度は「transition」で調節。

メニューを消したい場合は×印をクリックするとチェックボックスのチェックが外れます

それによりckeckedで設定していたデザインが適用されなくなって元に戻り

  • ×印が三本線に戻る
  • メニューは再び画面外へ飛ばされる

ということになります。

以上がCSSだけで作る簡単なハンバーガーメニューです。

ゆんつ
割と簡単な仕組みです

閉じるボタン無し

メニューを閉じるときに「×」のような閉じるボタンをつかわずに、画面の右端や左端などの一部の領域をクリックすると閉じるようにする方法もあります。

その方法とは、メニューに閉じるための要素をもう1つ作ってあげて、そこがクリックまたはタップされたらメニューを閉じるようにする方法です。

具体的に作ってみます。

See the Pen hamburger2 by konpure (@yuntu) on CodePen.

メニューアイコンをクリックしてメニューが現れたら、右端の赤い部分の好きな箇所をクリックしていただけたらメニューが閉じます。

HTML

<header class="header">
  <div class="logo">TEST</div><!-- /.logo -->

  <!-- ハンバーガーメニュー部分 -->
  <div class="drawer">
    <!-- ハンバーガーメニューの表示・非表示を切り替えるチェックボックス -->
    <input type="checkbox" id="drawer-check" class="drawer-hidden" >

    <!-- ハンバーガーアイコン -->
    <label for="drawer-check" class="drawer-open"><span></span></label>

    <!-- 追加:メニューを閉じるための要素 -->
    <label for="drawer-check" class="drawer-close"></label>

    <!-- メニュー -->
    <nav class="drawer-content">
      <ul class="drawer-list">
        <li class="drawer-item">
          <a href="">リンク1</a>
        </li><!-- /.drawer-item -->
        <li class="drawer-item">
          <a href="">リンク2</a>
        </li><!-- /.drawer-item -->
        <li class="drawer-item">
          <a href="">リンク3</a>
        </li><!-- /.drawer-item -->
      </ul><!-- /.drawer-list -->
    </nav>

  </div>
</header>

先ほどのhtmlと違うのはメニューを閉じるため用の要素が作られていることだけです。

閉じるための要素もラベル要素でチェックボックスと連動しており、この部分がクリックされるとチェックボックスのチェックが外れます。

CSS

.header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0 20px;
  background: #fff;
}

.logo {
  font-size: 24px;
}

/*------------------------------

  ここから下がハンバーガーメニュー
  に関するCSS

------------------------------*/
  
/* チェックボックスは非表示に */
.drawer-hidden {
  display: none;
}

/* ハンバーガーアイコンの設置スペース */
.drawer-open {
  display: flex;
  height: 60px;
  width: 60px;
  justify-content: center;
  align-items: center;
  position: relative;
  z-index: 98;/* 重なり順を一番下に */
  cursor: pointer;
}

/* ハンバーガーメニューのアイコン */
.drawer-open span,
.drawer-open span:before,
.drawer-open span:after {
  content: '';
  display: block;
  height: 3px;
  width: 25px;
  border-radius: 3px;
  background: #333;
  transition: 0.5s;
  position: absolute;
}

/* 三本線のうち一番上の棒の位置調整 */
.drawer-open span:before {
  bottom: 8px;
}

/* 三本線のうち一番下の棒の位置調整 */
.drawer-open span:after {
  top: 8px;
}
  
/* メニューのデザイン*/
.drawer-content {
  width: 70%;/* ここの割合を小さくすると閉じる部分の領域が広がる */
  height: 100%;
  position: fixed;
  top: 0;
  left: 100%;/* メニューを画面外へ */
  z-index: 100;/* 重なり順を一番上に */
  background: #fff;
  transition: .5s;
}

/* アイコンがクリックされたらメニューを表示 */
#drawer-check:checked ~ .drawer-content {
  left: 0;/* メニューを画面内へ */
}

/* メニューを閉じるための要素のデザイン*/
.drawer-close {
  width: 100%;
  height: 100%;
  background: red;
  position: fixed;
  top: 0;
  left: 100%;/* 閉じるための要素を画面外へ */
  z-index: 99;/* 重なり順をメニューより下に*/
  transition: .5s;
}

#drawer-check:checked ~ .drawer-close {
  left: 0;/* 閉じるための要素を画面内へ */
}

先ほどと違い×ボタンは必要ないので、×印をつくるためのCSSは消しています。

また、メニューが現れた時にボタンを表示する必要もないのでメニューアイコンの表示の優先順位を下げています。

閉じるための要素がチェックボックスと連動しているので、その部分をクリックするとチェックボックスのチェックが外れ、メニューが消えるようになっています。

リンク先がページ内リンクの場合

上記のように作成したハンバーガーメニューですが、そのメニューのリンク先が別ページへのリンクなら問題ありませんが、そのリンクがページ内リンクの場合には少し問題があります。

というのも、リンクのクリックではメニューが閉じないため、メニューが別のページへのリンクなら別のページに切り替わるため問題ないのですが、ページ内リンクの場合はリンクをクリックしてページ内の該当箇所に移動してもメニューが閉じずに開きっぱなしになるという問題です。

メニューのリンク先がページ内リンクの場合にはjQueryを利用して、リンクをクリックしたときにチェックボックスのチェックが外れるようなコードを書くと良いと思います。

上記のHTMLを例にするとこんな感じのコードになります。

//チェックボックスのチェックを外す
$(function() {
  $('.drawer-item>a').click(function() {
    $('#drawer-check').removeAttr('checked').prop('checked', false).change();
  });
});

これでメニューのページ内リンクをクリックしたら、メニューが閉じるようになるはずです。

See the Pen hamburger3 by konpure (@yuntu) on CodePen.

jQueryを利用するので、この場合「CSSだけ」というタイトルからは外れてしまいますが、そのあたりはどうかご容赦ください(笑)

ゆんつ
大目に見てね

仕組みが解れば難しくないです

以上がCSSだけで作るハンバーガーメニューの作り方です。

ラベルとチェックボックスを連動させ、CSSのchekedを利用してチェックボックスへのチェックの有無を確認して、メニューの表示・非表示の切り替えやメニューアイコンのアニメーションのきっかけを与えていることが解ったかと思います。

今回はハンバーガーメニューでしたが、チェックボックスとラベルとCSSのcheckedを使うことでクリックがあった場合のちょっとしたデザインの変更(クリックで要素の色を変えるなど)はjQueryを使わなくてもできるようになります。

上手に使っていきたいですね。

何かの参考になれば幸いです。

ゆんつ
それでは、またー。