スマホサイトでよくみるハンバーガーメニューの開閉ボタンのCSSをじっくりコーディング

メニューが開いているときはバツ印、メニューが閉じている時は3本線のハンバーガーになるボタンのCSSコーディングをじっくり解説します。ボタンの大きさが変わってもきれいなレイアウトを保つためにはひと工夫必要でした。

スマホサイトなどでよくみる、ハンバーガーメニューの開閉ボタンを実装する機会がありました。

Googleで検索すれば参考コードがたくさん出てくるので、拾ったコードをコピペして作ろうとしたのですが、案件に合わせてボタンの大きさを調整する際にバツ印のバランスが崩れたりしてしまいました。

7

(ボタンの大きさを変えるとバランスが崩れる・・・)

そこで、今後別の案件でも使いまわせるよう、ボタンの大きさによってレイアウトが崩れにくいCSSを書いたので、じっくり解説します。

作る順番

ボタンの中の見た目を、以下の順番で作っていきます。

  1. ボタンの中に3本の線を追加する

3

  1. 3本の線を中央に重ねて配置する

4

  1. ばつ印の状態を作る

5

  1. 上下の線を移動させてハンバーガーメニューの状態を作る

6

ちょっと変わった作り方に感じるかもしれませんが、いったんすべての線を中央に集めて先にばつ印を作る点が、崩れにくい見た目を作るために重要でした。

ボタンの見た目以外と機能をコーディング

まずはボタンの見た目以外の、開閉するメニューの部分を先に作ってしまいます。

htmlとjsを以下のようにします。

html
<div class="menu">
  <button class="menu__button">
  </button>
</div>
js(jQuery)
$('.menu__button').on('click',function(){
     $('.menu').toggleClass('menu--isOpen');
});

これで、.menu__buttonというクラスの要素をクリックすることで、.menuというクラスの要素にmenu--isOpenというクラスの付け外しができるようになりました。

このままでは見た目に変化がないので、menu--isOpenがあるときとないときに対応するスタイルを追加します。

css
.menu {
  position: fixed;
  top: 0;
  right: 0;
  width: 0;
  height: 100%;
  background-color: pink;
  transition: width .2s;
}

.menu--isOpen {
  width: 40vw;
}

.menu__button {
  position: fixed;
  right: 10px;
  top: 10px;
  width: 50px;
  height: 50px;
}

.menuの要素ははじめwidth0にしておき、.menu--isOpenがついたときだけwidth40vw;(ブラウザ幅の40%)にします。 メニューボタンは、親要素の.menuの状態にかかわらず右上固定とします。

上記のコードをCodePenなどにコピペすることで、装飾のないボタンを押して開閉するメニューの見た目が確認できます。 ※jQueryを使用しているため、jQueryを読み込む必要があります。

開いた状態

1

閉じた状態

2

ボタンに装飾を追加

ボタンにハンバーガーメニューの3本線を追加するため、htmlを以下のように変更します。

html
<div class="menu">
  <button class="menu__button">
    <span class="menu__lineTop"></span>    <span class="menu__lineMiddle"></span>    <span class="menu__lineBottom"></span>  </button>
</div>

追加した3つのspanが3本線の上・中央・下となります。

幅と高さを持たせ、背景色に黒い色を引くことで線の見た目を作ります。

css
(省略)

.menu span {
  display: block;
  width: 100%;
  height: 4px;
  background-color: #000;
  border-radius: 3px;
}

ここまでのボタンの見た目

3

くっついてしまっているのでちょっとわかりにくいのですが、3本の線が表示されるようになりました。

3本の線の位置を中心にまとめる

ここでちょっと変わった組み方をしますが、先ほど作った3本の線を、position: absoluteを使ってすべて中央に重ねます。

css
/*(省略)*/

.menu span {
  display: block;
  width: 80%;  margin: auto;  height: 4px;
  background-color: #000;
  border-radius: 3px;
  position: absolute;  left: 0;  right: 0;  top: calc((100% - 4px)/2)}

position: absolute;にしたことで線の幅がボタンの横幅いっぱいに広がってしまったので、widthの値を100%から80%に変更して、margin: auto;で中央に寄せています。

topプロパティだけcalcを使って少し複雑な値を指定しています。これは、ボタンの高さ100%から、線1本分の幅4pxを引いて、その半分の値を上からとるという指定です。こうすることで、縦位置中央に線が配置されます。

8

ここまでのボタンの見た目

4

重なっているので見た目上はわかりませんが、3本の線が中央に配置されています。

先に、メニューが開いているときのボタンの見た目を作る

3本の線が中央に重なっている状態から、ばつ印の形を作ります。真ん中の線は透明にして、上と下の線は時計回り・反時計回りにそれぞれ45度回転させます。

css
/*(省略)*/

.menu span {
  display: block;
  width: 80%;
  margin: auto;
  height: 4px;
  background-color: #000;
  position: absolute;
  left: 0;
  right: 0;
  top: calc((100% - 4px)/2);
  border-radius: 3px;
}

.menu--isOpen .menu__lineTop {  transform: rotate(45deg);}.menu--isOpen .menu__lineMiddle {  opacity: 0;}.menu--isOpen .menu__lineBottom {  transform: rotate(-45deg);  }

ここまでのボタンの見た目

これで、ばつ印の見た目ができました。ボタンを押すと、3本線の重なった状態とばつ印が切り替わることを確認できると思います。

4 5

メニューが閉じている時のハンバーガーメニューの見た目を作る

次に、メニューが閉じているときにハンバーガーメニューの3本線に見えるようそれぞれの線の位置を変更します。

css
/*(省略)*/

.menu span {
  display: block;
  width: 80%;
  margin: auto;
  height: 4px;
  background-color: #000;
  position: absolute;
  left: 0;
  right: 0;
  top: calc((100% - 4px)/2);
  border-radius: 3px;
}

.menu__lineTop {  transform: translateY(-10px);}.menu__lineMiddle {} /* 特に指定は無いので書かなくてもOK */.menu__lineBottom {  transform: translateY(10px);}
.menu--isOpen .menu__lineTop {
  transform: rotate(45deg);  
}

.menu--isOpen .menu__lineMiddle {
  opacity: 0;
}

.menu--isOpen .menu__lineBottom {
  transform: rotate(-45deg);  
}

transform: translateY()を使って、上の線は縦方向に-10px(上へ10px)、下の線は縦方向に10px(下へ10px)、元の位置(中央)から移動させます。この10pxの値は、ボタンの大きさやバランスに応じて調整してください。

これで、メニューが開いた状態と閉じた状態の両方の見た目ができました。

ここまでのボタンの見た目

6 5

アニメーションを追加し、見栄えを調整する

最後に、2つの見た目が滑らかに切り替わるようtransitionプロパティを追加し、0.2秒かけて見た目が変化するようにします。

また、ボタン要素にブラウザのデフォルトスタイルが当たっていてやや不格好なので、見栄えも調整します。

これで完成になるので、CSS全体を省略せず載せています。

css
.menu {
  position: fixed;
  top: 0;
  right: 0;
  width: 0;
  height: 100%;
  background-color: pink;
  transition: width .2s;
}

.menu--isOpen {
  width: 40vw;
}

.menu__button {
  position: fixed;
  right: 10px;
  top: 10px;
  width: 50px;
  height: 50px;
  background-color: rgba(200, 200, 230, .7);  border-radius: 5px;  border: none;}

.menu span {
  display: block;
  width: 80%;
  margin: auto;
  height: 4px;
  background-color: #000;
  position: absolute;
  left: 0;
  right: 0;
  top: calc((100% - 4px)/2);
  border-radius: 3px;
  transition: .2s;}

.menu__lineTop {
  transform: translateY(-10px);
}

.menu__lineMiddle {}

.menu__lineBottom {
  transform: translateY(10px);
}

.menu--isOpen .menu__lineTop {
  transform: rotate(45deg);  
}

.menu--isOpen .menu__lineMiddle {
  opacity: 0;
}

.menu--isOpen .menu__lineBottom {
  transform: rotate(-45deg);  
}

ここまでのボタンの見た目

9 10

これで完成です。

終わりに

まず縦位置中央に配置してからtransformプロパティで線を移動することで、ばつ印になったときの中心の位置が合わせやすくなりました。ボタンの大きさや線の幅が変わっても、調整する箇所は少なくすむと思います。

最終的なコードをご覧になりたい方は、以下のCodePenにアクセスしてください。

完成形のソースコードを見る

以上です。最後までお読みいただきありがとうございました。