クモのようにコツコツと

フロントエンドエンジニア イイダリョウの技術ブログ。略称「クモコツ」

【擬似クラス:target】CSSのみでハンバーガーメニューを作る

スマホの小さい画面でメニューをしまっておくのによく使われるハンバーガーメニュー 。これまでは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の中に#closeulリストが入っている
  • #closeは閉じるボタン(×)
  • ulリストはメニュー

開くボタン(三)とメニューが大きな塊で、閉じるボタン(×)はメニューの中に含まれています。

CSSのコード

#g_menu {
  /*中略*/
  transition: right 1s;
  position: fixed;
  top: 0;
}

.outside {
    right: -100%;
}

.inside {
    right: 0;
}
  • #g_menu:transitionアニメ1秒をpositionrightにかける
    positionfixedtopの位置は0
  • .outside#g_menuと同じ要素)のpositionright-100%
  • .inside(まだHTML上にない)のpositionrightを0に

メニューにはCSSアニメtransitionposition: fixed設定。positonの位置はtop設定のみ。

transitionアニメについてはこちらで解説しています。

※参考:スクロールするとフワッと現れたり動いたりするアニメーション【jquery.inview.js & transition】 - クモのようにコツコツと

positionright設定はクラス名.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)
  • positionright: 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