スマホの小さい画面でメニューをしまっておくのによく使われるハンバーガーメニュー 。これまではJSのクリックイベントでclass名を追加して実現してました。擬似クラス:target
を使うとCSSだけで実現できると知って試してみた。
【目次】
JS(クリックイベント)を使ったハンバーガー
これまでのハンバーガーメニュー。こんなです。
ヘッダー右上の開くボタン(三)を押すと右側からハンバーガーメニューが出てきます。メニューの中の閉じるボタン(×)を押すとメニューが閉じる。
HTMLのコード
<nav> <div id="open" class="btn"><a href="#g_menu">三</a></div> <div id="g_menu" class="outside"> <div id="close" class="btn"><a href="#">×</a></div> <ul> <li><a href="#title1">メニュー1</a></li> <li><a href="#title2">メニュー2</a></li> <li><a href="#title3">メニュー3</a></li> <li><a href="#title4">メニュー4</a></li> <li><a href="#title5">メニュー5</a></li> <li><a href="#title6">メニュー6</a></li> <li><a href="#title7">メニュー7</a></li> </ul> </div> </nav>
nav
要素の中に#open
と#g_menu
が入っている#open
はハンバーガーメニューの開くボタン(三)#g_menu
にはクラス名.outside
も付いている#g_menu
の中に#close
とul
リストが入っている#close
は閉じるボタン(×)ul
リストはメニュー
開くボタン(三)とメニューが大きな塊で、閉じるボタン(×)はメニューの中に含まれています。
CSSのコード
#g_menu { /*中略*/ transition: right 1s; position: fixed; top: 0; } .outside { right: -100%; } .inside { right: 0; }
#g_menu
:transition
アニメ1秒をposition
のright
にかける
position
はfixed
、top
の位置は0
に.outside
(#g_menu
と同じ要素)のposition
のright
を-100%
に.inside
(まだHTML上にない)のposition
のright
を0に
メニューにはCSSアニメtransition
とposition: fixed
設定。positon
の位置はtop
設定のみ。
transition
アニメについてはこちらで解説しています。
※参考:スクロールするとフワッと現れたり動いたりするアニメーション【jquery.inview.js & transition】 - クモのようにコツコツと
position
のright
設定はクラス名.outside
、.inside
の方に書いています。
.outside
は右に-100%
つまり自分の幅分ページの外側に配置されちる。.inside右に
0`つまり画面右端だが、まだHTML上にない。
JSのコード
const open = document.querySelector("#open"); const close = document.querySelector("#close"); const g_menu = document.querySelector("#g_menu"); //メニューを出す open.addEventListener('click', function() { g_menu.classList.add('inside'); g_menu.classList.remove('outside'); }, false); //メニューを隠す close.addEventListener('click', function() { g_menu.classList.remove('inside'); g_menu.classList.add('outside'); }, false);
- 変数
open
と#open
、変数close
と#close
、変数g_menu
と#g_menu
を紐付け open
をクリックしたとき、g_menu
にクラス名inside
追加、クラス名remove
削除close
をクリックしたとき、g_menu
にクラス名inside
削除、クラス名remove
追加
メニューの位置やアニメはすべてCSS上に書いているので、JSではクリックイベントでclass名を追加、削除するだけ。inside
を追加するとメニューがページ外から右端に移動する。
これはCSSマリオをジャンプさせた時と同じ方法。
※参考:CSSドット絵マリオをCSSアニメでジャンプさせてみる - クモのようにコツコツと
CSS(擬似クラス:target)のみのハンバーガー
さて、これまではこの方法で作ってきたのですが、擬似クラス:target
を使うとJSなしでCSSのみで実現できそうでした。
※参考:[CSS]知ってると便利!「:target疑似クラス」を使ったスタイルシートのテクニックと注意点 | コリス
:target
はページ内リンクのa
タグをクリックした時に指定先のid名のタグに当たるスタイルです。
実際にやってみた。
どうですか!動作に関しては最初のJSを使ったハンバーガーメニューと全く同じじゃないですか!でも「JS」のタブを開くと1行も書かれていないことがわかります。いったいどう変わったのか?
HTMLコード
<nav> <div id="open" class="btn"><a href="#g_menu">三</a></div> <div id="g_menu"> <div id="close" class="btn"><a href="#">×</a></div> <ul> <li><a href="#title1">メニュー1</a></li> <li><a href="#title2">メニュー2</a></li> <li><a href="#title3">メニュー3</a></li> <li><a href="#title4">メニュー4</a></li> <li><a href="#title5">メニュー5</a></li> <li><a href="#title6">メニュー6</a></li> <li><a href="#title7">メニュー7</a></li> </ul> </div> </nav>
#g_menu
にあったクラス名.outside
はここでは付いていない
HTML上の違いはほとんどありませんね。#g_menu
にクラス名がなくなったくらい。
CSSコード
#g_menu { /*中略*/ transition: right 1s; position: fixed; top: 0; } #g_menu:not(:target) { right: -100%; } #g_menu:target { right: 0; }
position:
のright: -100%
は.outside
ではなく#g_menu:not(:target)
にposition
のright: 0
は.inside
ではなく#g_menu:target
に
ここに擬似クラス:target
が入ります。開くボタン(三)のリンク先は#g_menu
なので開くボタンを押した時にページ外にあるメニューが画面右端に移動します。
1行目の:not()
は以前こちらで解説しました。
※参考:【CSS】擬似クラス:not()があまりにも素敵すぎでしょう、君ぃ! - クモのようにコツコツと
:not(:target)
は:target
以外、つまり開くボタン(三)を押したとき以外はメニューがページ外という設定。そのため閉じるボタンやメニューをクリックするとページ外に移動します。
scroll-behavior: smooth(CSSだけでスムーススクロール)
もう一つ、今回知ったCSSがありました。scroll-behavior: smooth
といってJSを使わずにCSSだけでページ内リンクのスムーススクロールを実現する方法です。
※参考:ページ内のスムーススクロールをCSSのみで実装する方法 | KuzLog
html { scroll-behavior: smooth; }
実際にやっみたので、ハンバーガーメニューの中の「メニュー1」とかを押してみてください。
っと、先ほどの記事にもあったように、どうやらSafariでは動かない模様。
※参考:Can I use... Support tables for HTML5, CSS3, etc
対応が待たれますねー。
それまではこれまで通りJSを使いませう。
※参考:jQueryでスムーススクロールを実装する方法 | TechAcademyマガジン
※参考:【JavaScript】超軽量スムーススクロール『MoveTo』をご紹介! - ONZE
最後に
クリックイベントの代替に使えそうなCSS:target
。こちらのブラウザ対応はバッチリのようですよ!
※参考:Can I use... Support tables for HTML5, CSS3, etc
CSSで完結できることがどんどん増えていくのは嬉しい限りです。昔はアニメーションの設定値もJSに書いてましたからね〜。それではまた!
※参考:ネイティブHTML & CSSやってみたシリーズ
qiita.com