CSSだけで作るアニメーション付きのハンバーガーメニュー
AlexaTopSitesが、お前のサイトでハンバーガーメニューの記事がないのはもったいないよ!アニメーションも付けろよ!としつこく言ってくるので作ってみます。
この記事はHTMLとCSSでやります。
ハンバーガーメニューのボタンはいくつかアニメーションのサンプルを用意してあります
状況によってはjsを使わないといけない場面が出てきますがそこらへんは別の記事で
この記事の目次
ハンバーガーメニューとは
googleで検索すると一番上にこう出てきます。
ハンバーガーメニューとは、サイト内の三本線のナビゲーションメニューで、クリックすると隠れている情報が表示される仕組み。 主にスマートフォンのUIデザインとして用いられている。
ハンバーガーメニューには賛否あると思いますが、大体のデザイナーはこれを実装しろと言ってくるので作り方を覚えておいて問題はないと思います。
ハンバーガーメニューのボタン部分を作る
ハンバーガーメニューのボタン部分は画像をそのまま貼り付けているサイトだったり、クリック・タップしたらバツ印に画像が変わったりあると思いますが、この記事では要素を使ってボタンを作り、checked疑似クラスを使ってアニメーションするように実装していきます。
まずはHTMLから、
チェックボックスはクリック判定用に用意
label要素はその中に作るハンバーガーメニュー用のボタンとチェックボックスを関連付けるために用意しました。
1 2 3 4 5 6 7 8 |
<input type="checkbox" id="menu_checkbox"> <label for="menu_checkbox" id="menu_label"> <span class="menu_btn"> <span></span> <span></span> <span></span> </span> </label> |
HTMLの用意ができたら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 |
.menu_btn { display: inline-block; position: relative; width: 26px;/*ボタン全体の幅を変えたいならここを調整*/ height: 21px;/*ボタン全体の高さを変えたいならここを調整*/ cursor: pointer; } .menu_btn span { display: inline-block; width: 100%; height: 3px;/*ボタン内の三本線の太さを変えたいならここを調整*/ background-color: #000;/*ボタン内の三本線の色を変えたいならここを調整*/ transition: .4s;/*アニメーション時間*/ box-sizing: border-box; position: absolute; left: 0; } /*ボタン全体の高さか線の太さを調整したらここも調整しないときれいに表示されませぬ*/ .menu_btn span:nth-of-type(1) { top: 0; } .menu_btn span:nth-of-type(2) { top: 9px; } .menu_btn span:nth-of-type(3) { bottom: 0; } |
見やすいように多少の小細工をしていますが、よく見るハンバーガーボタンができました。
ボタンクリックでチェックボックスの状態が変化するところも確認しておいてください
これで見た目だけは完成しました
ハンバーガーボタンのアニメーション
クリックしたときのアニメーションは、checked疑似クラスと~(チルダ)を組み合わせて設定していきます。
いくつかサンプルとコードを用意しておきましたので前述したコードに追加して確認してみてください
~(チルダ)を使うと同じ階層にあるあとに記述してある要素を指定できるようになります。
『#menu_checkbox:checked ~ #menu_label』とすれば、チェックがついたチェックボックスのあとにある同じ階層の#menu_labelを操作できます。
#menu_labelの子要素まで絞り込むことができるので今回のケースでは便利です
シンプルなアニメーション
上と下の線が角度を変えてバツ印になりつつ、真ん中の線は消えるといった、よく見るシンプルなアニメーションであれば簡単だと思います。
transformプロパティを使って真ん中の線の位置に移動しつつ角度を変えてみましょう
1 2 3 4 5 6 7 8 9 10 11 |
#menu_checkbox:checked ~ #menu_label .menu_btn span:nth-of-type(1) { transform: translateY(9px) rotate(-45deg); } #menu_checkbox:checked ~ #menu_label .menu_btn span:nth-of-type(2) { opacity: 0; } #menu_checkbox:checked ~ #menu_label .menu_btn span:nth-of-type(3) { transform: translateY(-9px) rotate(45deg); } |
※ 触ると動きます
いっぱいぐるぐる回るアニメーション
前述したシンプルなものの角度を調整すれば回転数を増やすことができます。
1 2 3 4 5 6 7 8 9 10 11 |
#menu_checkbox:checked ~ #menu_label .menu_btn span:nth-of-type(1) { transform: translateY(9px) rotate(-405deg); } #menu_checkbox:checked ~ #menu_label .menu_btn span:nth-of-type(2) { opacity: 0; } #menu_checkbox:checked ~ #menu_label .menu_btn span:nth-of-type(3) { transform: translateY(-9px) rotate(405deg); } |
※ 触ると動きます
真ん中の線が横移動して消えるアニメーション
前述したシンプルなものをベースに真ん中のものが移動して消えるような動きも可能です。
必要に応じてoverfloWプロパティと組み合わせて使うといいと思います
1 2 3 4 5 6 7 8 9 10 11 12 |
#menu_checkbox:checked ~ #menu_label .menu_btn span:nth-of-type(1) { transform: translateY(9px) rotate(-45deg); } #menu_checkbox:checked ~ #menu_label .menu_btn span:nth-of-type(2) { left: 100%; opacity: 0; } #menu_checkbox:checked ~ #menu_label .menu_btn span:nth-of-type(3) { transform: translateY(-9px) rotate(45deg); } |
※ 触ると動きます
常時アニメーションさせておく
すこしずれてしまいますが、常時ハンバーガーメニューを利用させるようなサイトであればボタン自体をアニメーションで動かしておいても面白そうですね。
そのまま使えるようにしてあるのでちょっとコードは長め
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 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
.menu_btn { display: inline-block; position: relative; width: 26px; height: 21px; cursor: pointer; } .menu_btn span { display: inline-block; width: 100%; height: 3px; background-color: #000; transition: .4s; box-sizing: border-box; position: absolute; right: 0; border-radius: 3px; } .menu_btn span:nth-of-type(1) { top: 0; width: calc(100% - 4px); animation:line1 1s linear infinite; } .menu_btn span:nth-of-type(2) { top: 9px; width: calc(100% - 7px); animation:line2 1s linear infinite; } .menu_btn span:nth-of-type(3) { bottom: 0; animation:line3 1s linear infinite; } @keyframes line1{ 0%{ width: calc(100% - 4px); } 25%{ width: calc(100% - 2px); } 50%{ width: calc(100% - 4px); } 75%{ width: calc(100% - 6px); } 100%{ width: calc(100% - 4px); } } @keyframes line2{ 0%{ width: calc(100% - 7px); } 25%{ width: calc(100% - 9px); } 50%{ width: calc(100% - 7px); } 75%{ width: calc(100% - 5px); } 100%{ width: calc(100% - 7px); } } @keyframes line3{ 0%{ width: 100%; } 50%{ width: calc(100% - 9px); } 100%{ width: 100%; } } #menu_checkbox:checked ~ #menu_label .menu_btn span:nth-of-type(1) { transform: translateY(9px) rotate(-225deg); width: 100%; animation:none; } #menu_checkbox:checked ~ #menu_label .menu_btn span:nth-of-type(2) { right: 100%; opacity: 0; width: 100%; animation:none; } #menu_checkbox:checked ~ #menu_label .menu_btn span:nth-of-type(3) { transform: translateY(-9px) rotate(225deg); width: 100%; animation:none; } |
※ 触ると動きます
色々と思いつくかと思ったのですが思いつきませんでしたので紹介できるのはこれだけです
工夫すれば色々な動きを出すことができると思うのでやってみてください
あとはこのボタンをサイト内に組み込んで状態に応じて要素を出したり消したりするだけです
ハンバーガーメニューのボタンをサイトに組み込む
とりあえずサンプルです。レスポンシブとかではなく、常時ハンバーガーメニューを表示しているタイプになります。
私がよく作る形だとこのような形のベースを作ります
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<header class="header"> <div class="header_inner"> <h1 class="logo">マクダーナル</h1> <nav class="gnav"> <ul class="gnav_list"> <li class="gnav_item"><a href="#" class="gnav_link">ホーム</a></li> <li class="gnav_item"><a href="#" class="gnav_link">メニュー</a></li> <li class="gnav_item"><a href="#" class="gnav_link">キャンペーン</a></li> <li class="gnav_item"><a href="#" class="gnav_link">ファミリー</a></li> </ul> </nav> </div> </header> |
チルダを使ってハンバーガーメニューのボタンがクリックされて、チェックボックスにチェックが入っている場合はナビゲーションを表示したり、チェックが入っていないときは非表示にしたり、cssを切り替えていきますのでそれを前提にコードを作る必要があります。
チェックボックス・閉じるための背景・ハンバーガーメニューのボタン・ナビゲーションが同一階層で兄弟になるようにマークアップしつつ、チェックボックスを長男の位置(先頭)に配置していきます
操作するものは同一階層にすることが、cssで作るハンバーガーメニューのキモになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<header class="header"> <div class="header_inner"> <h1 class="logo">マクダーナル</h1> <input type="checkbox" id="menu_checkbox"> <label for="menu_checkbox" id="background"></label> <label for="menu_checkbox" id="menu_label"> <span class="menu_btn"> <span></span> <span></span> <span></span> </span> </label> <nav class="gnav"> <ul class="gnav_list"> <li class="gnav_item"><a href="#" class="gnav_link">ホーム</a></li> <li class="gnav_item"><a href="#" class="gnav_link">メニュー</a></li> <li class="gnav_item"><a href="#" class="gnav_link">キャンペーン</a></li> <li class="gnav_item"><a href="#" class="gnav_link">ファミリー</a></li> </ul> </nav> </div> </header> |
cssはいらない要素を消すところから始めます。
ページを開いた状態では、チェックボックス・閉じるための背景・ナビゲーションメニューはハンバーガーメニューのボタンがクリックまたはタップされた時に表示したいので、一旦非表示にしておきます。
非表示にする場合、チェックボックスはシンプルに「display:none;」で非表示にしてしまえばいいと思いますが、アニメーションを付けたい閉じるための背景や、ナビゲーションメニューは「display:none;」を使わずに、「width」や「height」を0にしておくとアニメーションが付けやすいのでよくこの方法を使っています。
ウインドウに固定したり文字をいじったり余計なものも入っていますがそのへんはお好みで調整してください
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 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
.header{ width: 100%; position: fixed; top: 0; left: 0; box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.5); z-index: 100; background-color: #fff; } .header_inner{ max-width: 1500px; height: 60px; padding:20px; position: relative; display: flex; align-items: center; justify-content: space-between; } .logo{ font-family: 'Train One', cursive; font-size: 20px; color: #FFBC0D; } #menu_checkbox{ display: none; } #background{ display: block; z-index: 9; position: fixed; top: 60px; left: 0; width: 100%; height: 0; transition: .4s; background-color: #d6d6d6; } .gnav{ position: fixed; top: 60px; left: 0; width: 100%; height: 0; overflow-y: hidden; padding:0; transition: .4s; z-index: 10; } .gnav_item { font-weight: bold; text-align: center; opacity: 0; transition: .4s .4s; } .gnav_link{ text-decoration: none; color: #000; } .menu_btn { display: inline-block; position: relative; width: 26px; height: 21px; cursor: pointer; } .menu_btn span { display: inline-block; width: 100%; height: 3px; background-color: #000; transition: .4s; box-sizing: border-box; position: absolute; right: 0; border-radius: 3px; } .menu_btn span:nth-of-type(1) { top: 0; width: calc(100% - 4px); animation:line1 1s linear infinite; } .menu_btn span:nth-of-type(2) { top: 9px; width: calc(100% - 7px); animation:line2 1s linear infinite; } .menu_btn span:nth-of-type(3) { bottom: 0; animation:line3 1s linear infinite; } @keyframes line1{ 0%{ width: calc(100% - 4px); } 25%{ width: calc(100% - 2px); } 50%{ width: calc(100% - 4px); } 75%{ width: calc(100% - 6px); } 100%{ width: calc(100% - 4px); } } @keyframes line2{ 0%{ width: calc(100% - 7px); } 25%{ width: calc(100% - 9px); } 50%{ width: calc(100% - 7px); } 75%{ width: calc(100% - 5px); } 100%{ width: calc(100% - 7px); } } @keyframes line3{ 0%{ width: 100%; } 50%{ width: calc(100% - 9px); } 100%{ width: 100%; } } #menu_checkbox:checked ~ #menu_label .menu_btn span:nth-of-type(1) { transform: translateY(9px) rotate(-225deg); width: 100%; animation:none; } #menu_checkbox:checked ~ #menu_label .menu_btn span:nth-of-type(2) { right: 100%; opacity: 0; width: 100%; animation:none; } #menu_checkbox:checked ~ #menu_label .menu_btn span:nth-of-type(3) { transform: translateY(-9px) rotate(225deg); width: 100%; animation:none; } |
最後にチェックボックスにチェックが入っているときのスタイルを追加したら完成になります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#menu_checkbox:checked ~ #background{ height: calc(100vh - 60px); } #menu_checkbox:checked ~ .gnav { max-height: calc(100vh - 60px); height: auto; padding: 45px 0 50px; } #menu_checkbox:checked ~ .gnav .gnav_item { opacity: 1; margin-bottom: 24px; } |
これでcssだけで作るハンバーガーメニューは完成になりますが、ページ内リンクには対応できないので、ナビゲーションの中にページ内リンクが有る場合は、jsを使って制御するしかありません。
サイトの構造を選ぶ形にはなってしまいますが、簡単なjsで対応可能なので、ベースとして使ってもいいのではないかと思います。