[CSS]Flexboxでハンバーガーメニューを作ろう

プラグインやフレームワークを使わずにレスポンシブ対応のナビゲーションが作れないかとここ1年半ほどずっと考えていました。制作現場では時間の制約などの関係でプラグインの導入が現実的だと思うのですが、せっかく勉強しているので、今回はFlexboxを使ってレスポンシブ対応のナビゲーションメニューを作ってみました。
実装手順
手順は以下です。
- マークアップ
- Flexboxで並べる
- ブレイクポイントでレイアウトを切り替える
- スクリプトを書く
- ハンバーガーメニューを作る
実際に作ってみましょう
初めてハンバーガーメニューを実装する場合、訳が分からなくなるかもしれませんが、テンプレートのようなものなので、この際覚えておきましょう。
1.マークアップ
よく見かけるロゴとメニューが横並びのレイアウトの文書構造を書いていきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <header> <nav> <h1>Panda Custom</h1> <ul> <li><a href="#">menu 1</a></li> <li><a href="#">menu 2</a></li> <li><a href="#">menu 3</a></li> <li><a href="#">menu 4</a></li> </ul> <div class="nav__icon"> <span></span> <span></span> <span></span> </div> </nav> <!--/Nav--> </header> <!--/Header--> |
<div class=”nav__icon”> で始まる構造は、ハンバーガーメニューで見かける3本線を作るためのアイコン部分です。
2.Flexboxで並べる
Flexboxについて、僭越ながら記事を書いていますので、よかったら参考にしてください。
まず、CSSリセットをかけておきます。
簡単なのはユニバーサルセレクタリセットです。
1 2 3 4 | * { margin: 0; padding: 0; } |
他にもあるので、別の記事で紹介したいと考えています。
それでは <nav> 部分を Flexbox で並べていきましょう。
1 2 3 4 5 6 | nav { display: -webkit-flex; display: flex; -ms-align-items: center; align-items: center; } |
垂直方向の中央揃えは align-items: center; でしたね。
ついでに、ロゴ部分とメニューは今回離して表示したいので、<h1>には margin-right: auto; 、ハンバーガーメニューの3本線を非表示にしておきたいので display: none; をかけておきます。
すると、こんな感じに…
See the Pen FlexBox Responsive Menu(Stub1) by necomacustom (@tamayura) on CodePen.27739
…って、おや?
そうなんです、<nav>の子要素が<h1>と<ul>なので、 display: flex; をかけるとすぐ下の子要素だけが横並びになるんですね。
という訳で、もう一つコードを足していきます。
1 2 3 4 5 | ul { display: -webkit-flex; display: flex; list-style: none; } |
<li>に対して横並びをかけています。
今度はどうでしょう。
See the Pen FlexBox Responsive Menu(Stub2) by necomacustom (@tamayura) on CodePen.27739
これで揃いました。CSSボタンを押すと記述内にリセットのコードがないのですが、Codepenの機能でリセットをかけてあります。
3.ブレイクポイントでレイアウトを切り替える
一定のウィンドウサイズになったら、横並びになっているメニューを縦方向に並び変えるようにしていきます。
flex-direction: column; で子要素を上から順に並べることができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | @media (max-width:700px){ a{ padding: 0px; } ul{ width: 100%; background-color: rgba(0, 0, 0, .8); -webkit-flex-direction: column; flex-direction: column; } li{ text-align: center; } } |
今回はブレイクポイントを700pxに設定してみます。
See the Pen FlexBox Responsive Menu(Stub3) by necomacustom (@tamayura) on CodePen.27739
ウィンドウ幅を狭めるとこのような感じになります。ここからさらに変えていきたいのですが…そう、ハンバーガーメニューはどうなった?って話ですよね。
先にスクリプトを書いてから、説明します。
4.スクリプトを書いてクリックイベントを発生させる
今回のハンバーガーメニューは、ブレイクポイントの切り変えに応じて表示させて、<span>を線として描写して、<div class=”nav__icon”>(ハンバーガーアイコン) をクリックすると×印に変わり、縦に並んだメニューがスルッと降りてくるようなタイプのものを作りたいので、それについての記述をしていきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | $(function(){ $(".nav__icon").on("click", function() { $(this).toggleClass("active"); $("nav ul").slideToggle(); }); $(window).resize(function(){ var w = $(window).width(); var h = $(window).height(); var x = 700; if (w >= x) { $('nav ul').css({ display: 'flex',height: 'auto' }); }else { $('nav ul').css({ display: 'none',height: h + 'px'}); } }); }); |
あ、jQueryは忘れずに読み込ませてくださいね。
2行目にハンバーガーアイコンをクリックした時の機能を、3行目に.nav__icon
が付いている要素にクリックによって.active
のクラス名を追加したり削除したりが可能です。同時にメニューにあたる<ul>が表示/非表示を変える、といった4行目を書いています。
実はこれだけでも動くのですが、さらに下にブレイクポイント(700px以下)で切り替えた時にメニューを非表示にしておくために書いています。
12行目の700px以上のウィンドウサイズの時には<ul>に display: ‘flex’ と height: ‘auto’ のプロパティを追加するという記述は…必要かどうかが微妙に感じたので、<ul>部分のCSSを削除して確認してみました…一時的に表示が崩れますね。ちょっと困るかも。
5.ハンバーガーメニューをCSSで作る
さて、最初の章でマークアップしたハンバーガーアイコン <div class=”nav__icon”> はどうなるのか…ですよね。
とりあえずCSSを書いてみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | .nav__icon { width: 36px; height: 28px; position: relative; cursor: pointer; } .nav__icon span { background: rgba(255, 255, 255, 1); position: absolute; left: 0; width: 100%; height: 4px; border-radius: 4px; } .nav__icon span:nth-of-type(1) { top: 0; } .nav__icon span:nth-of-type(2) { top: 12px; } .nav__icon span:nth-of-type(3) { bottom: 0; } .nav__icon.active span:nth-of-type(1) { -webkit-transform: translateY(12px) rotate(-45deg); transform: translateY(12px) rotate(-45deg); } .nav__icon.active span:nth-of-type(2) { display: none; } .nav__icon.active span:nth-of-type(3) { -webkit-transform: translateY(-12px) rotate(45deg); transform: translateY(-12px) rotate(45deg); } @media only screen and (max-width: 700px) { .nav__icon, .nav__icon span { display: inline-block; transition: all .4s; box-sizing: border-box; z-index: 999; } } |
…これは、説明を省きたくなるボリュームですね(苦笑)。くじけずにいきます。
文章にすると長くなりそうだったので、急遽ハンバーガーアイコンの概要を図にしてみました。
ハンバーガーアイコン全体(<div class=”nav__icon”>)を position: relative; にしておいて、線部分(<span>)の位置を position: absolute; で決めます。
線部分をそれぞれ :nth-of-type()
の擬似要素を使って位置を決めています。
コードでは前半部分にあたります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | .nav__icon { width: 36px; height: 28px; position: relative; cursor: pointer; } .nav__icon span { background: rgba(255, 255, 255, 1); position: absolute; left: 0; width: 100%; height: 4px; border-radius: 4px; } .nav__icon span:nth-of-type(1) { top: 0; } .nav__icon span:nth-of-type(2) { top: 12px; } .nav__icon span:nth-of-type(3) { bottom: 0; } |
次に、jQueryで書いたアイコンをクリックするイベント発生時…言い換えると<div class=”nav__icon”>に.active
のクラス名が追加された時の挙動をさらに書いていきます。
transformプロパティを使って<span>を動かします。
この transform は文字や画像を拡大・縮小、移動、回転などを指定出来るプロパティです。
今回は要素を垂直方向に移動させる translateY()
と、回転させる rotate()
を使って上の線と下の線を動かして、真ん中の線を display: none; で非表示にしています。
それぞれ、
- 上の線は「12px下方向に移動して、-45度回転する」
- 下の線は「12px上方向に移動して、45度回転する」
ということをしています。ここまでが後半部分です。
1 2 3 4 5 6 7 8 9 10 11 12 13 | .nav__icon.active span:nth-of-type(1) { -webkit-transform: translateY(12px) rotate(-45deg); transform: translateY(12px) rotate(-45deg); } .nav__icon.active span:nth-of-type(2) { display: none; } .nav__icon.active span:nth-of-type(3) { -webkit-transform: translateY(-12px) rotate(45deg); transform: translateY(-12px) rotate(45deg); } |
最後は700px以下の時にハンバーガーアイコンを表示させるコードなのですが、ここには transitionプロパティ がありますね。
transition は「時間変化」を指定する際に使うプロパティです。
今回はショートハンドで書いていますが、0.4秒かけてゆっくりと×印になるような設定です。
かなり長くなりましたが、これで完成です。
少しCSSをいじってありますが、完成サンプルはこちらです。
See the Pen FlexBox Responsive Menu-css by necomacustom (@tamayura) on CodePen.27739
HTMLかCSSのボタンを押せばウィンドウ幅が狭まりますので、確認できます。
お疲れ様でした!
初めてのハンバーガーメニューについての説明だったので、長くなってしまいました(^^;)
個人的にはアクセシビリティや操作性などでやや不安があるため「ハンバーガーメニューをあまり使うのもどうかなー」と思っているのですが、「お客さんの要望としてあったりする…」ということもたまに見聞きするので、実装できるに越したことはないですね。
他に簡単に実装できるプラグインもあるので当ブログでも紹介していけたらと思います。ねこま(@necomacustom)でした。