LoginSignup
2
3

More than 3 years have passed since last update.

CSSのみで実装するハンバーガーメニュー

Last updated at Posted at 2020-06-02

はじめに

スマホ用ページなどでよく利用される、「ハンバーガーメニュー」をCSSのみで実装して見ます。
あくまで機能面の実装を目的としているので、デザイン面でのCSSは省略しています。

基本のHTML構造

<header class="header">
  <h1><a href="index.html">TITLE</a></h1>
  <div class="menu-trigger">
    開く
  </div>
  <nav id="top-nav" class="nav-menu">
    <ul>
      <li><a href="index.html">HOME</a></li>
      <li><a href="about.html">ABOUT</a></li>
      <li><a href="contact.html">CONTACT</a></li>
    </ul>
  </nav>
</header>

ハンバーガーメニューの実装イメージ

スクリーンショット 2020-06-02 10.01.41(2).png

「開く」ボタンと「閉じる」ボタンを押すことでメニューの開閉をする簡単な構造になります。

titleとmenuを両端に配置

.header{
  display: flex;
  justify-content: space-between;
}

flexboxを使って、左右両端に配置します。

nav-menuを右上に固定

.header{
  position: relative;
}
.nav-menu{
  position: absolute;
  top: 0;
  right: 0;
}

position:absoluteを使って位置を固定しています。
その際、基準となるheaderにposition: relativeを設定します。

メニュー開閉の仕組みを作る

メニュー開閉の仕組みは、cssのtarget属性にて実装します。

<header class="header">
  <h1><a href="index.html">TITLE</a></h1>
  <div class="menu-trigger">
    <a href="#top-nav">開く</a>
  </div>
  <nav id="top-nav" class="nav-menu">
    <a href="#!" class="menu-close">閉じる</a>
    <ul>
      <li><a href="index.html">HOME</a></li>
      <li><a href="about.html">ABOUT</a></li>
      <li><a href="contact.html">CONTACT</a></li>
    </ul>
  </nav>
</header>

aタブを用いて、対象のid属性を指定しています。
閉じるボタンの href="#!" は、ターゲットを外す目的で指定しています。

.nav-menu:not(:target){
}
.nav-menu:target{
}

非表示のスタイルを :not(:target)
表示スタイルを :target に記述します。

nav-menuを非表示にする

.nav-menu:not(:target){
  opacity: 0;
  visibility: hidden;
}

opacityで透明度を0に、visibility: hiddenで非表示にしています。

メニュー表示時、nav-menuを表示させる

.nav-menu:target{
  opacity: 1;
  visibility: visible;
}

opacityで透明度を1に、visibility: visibleで表示しています。

開閉時のフェードイン・アウト

.nav-menu:not(:target){
  transition: 1s;
}
.nav-menu:target{
  transition: 1s;
}

transitionでプロパティ変化の時間を指定しています。

閉じるボタンを右上に固定する

.menu-close{
  position: absolute;
  top: 0;
  right: 0;
}

position:absoluteを使って位置を固定しています。

各要素の重なり具合を調整する

下から

  • header(body)
  • menu-trigger
  • nav-menu

の順番で重なるようにz-indexを指定していきます

.menu-trigger{
  position: relative;
  z-index: 2;
}
.nav-menu{
  z-index: 3;
  background: white;
}

z-indexは、positionプロパティが設定されていないと適応されないため、position: relativeを追記しています。
nav-menuは、menu-triggerを隠すため、背景色をつけています。

ここまでのまとめ

<header class="header">
  <h1><a href="index.html">TITLE</a></h1>
  <div class="menu-trigger">
    <a href="#top-nav">開く</a>
  </div>
  <nav id="top-nav" class="nav-menu">
    <a href="#!" class="menu-close">閉じる</a>
    <ul>
      <li><a href="index.html">HOME</a></li>
      <li><a href="about.html">ABOUT</a></li>
      <li><a href="contact.html">CONTACT</a></li>
    </ul>
  </nav>
</header>
.header{
  display: flex;
  justify-content: space-between;
  position: relative;
}
.nav-menu{
  position: absolute;
  top: 0;
  right: 0;
  z-index: 3;
  background: white;
}
.nav-menu:not(:target){
  opacity: 0;
  visibility: hidden;
  transition: 1s;
}
.nav-menu:target{
  opacity: 1;
  visibility: visible;
  transition: 1s;
}
.menu-close{
  position: absolute;
  top: 0;
  right: 0;
}
.menu-trigger{
  position: relative;
  z-index: 2;
}

レスポンシブ対応

PC版とスマホ版でCSSを切り替えます。

<head>
 <meta name="viewport" content="width=device-width, initial-scale=1">
</head

cssにてメディアクエリを使用するため、headタグにてviewportを読み込みます。

PC版のスタイルは

.header{
  display: flex;
  justify-content: space-between;
  position: relative;
}
.nav-menu{
  display: block;
}
.nav-menu ul{
  display: flex;
  justify-content: space-between;
}
.nav-menu li{
  padding-left: 10px;
}
.menu-close{
  display: none;
}
.menu-trigger{
  display: none;
}

で作られているものとして話を進めます。

メディアクエリの実装

PCとスマホのCSSで異なる点を記述してみます。

-- 共通 --
.header{
  display: flex;
  justify-content: space-between;
  position: relative;
}

.nav-menu{
-- PC --
  display: block;
-- スマホ --
  position: absolute;
  top: 0;
  right: 0;
  z-index: 3;
  background: white;
}

-- PC --
.nav-menu ul{
  display: flex;
  justify-content: space-between;
}
.nav-menu li{
  padding-left: 10px;
}

-- スマホ --
.nav-menu:not(:target){
  opacity: 0;
  visibility: hidden;
  transition: 1s;
}
.nav-menu:target{
  opacity: 1;
  visibility: visible;
  transition: 1s;
}


.menu-close{
-- PC --
  display: none;
-- スマホ --
  position: absolute;
  top: 0;
  right: 0;
}


.menu-trigger{
-- PC --
  display: none;
-- スマホ --
  position: relative;
  z-index: 2;
}

今回はスマホ版をデフォルトとし、PC版をメディアクエリで変更していきます。

.header{
  display: flex;
  justify-content: space-between;
  position: relative;
}

.nav-menu{
  position: absolute;
  top: 0;
  right: 0;
  z-index: 3;
  background: white;
}
@media screen and (min-width: 1000px){
.nav-menu{
  display: block;
}
}

@media screen and (min-width: 1000px){
.nav-menu ul{
  display: flex;
  justify-content: space-between;
}
}

@media screen and (min-width: 1000px){
.nav-menu li{
  padding-left: 10px;
}
}

@media screen and (max-width: 1000px){
.nav-menu:not(:target){
  opacity: 0;
  visibility: hidden;
  transition: 1s;
}
}
@media screen and (max-width: 1000px){
.nav-menu:target{
  opacity: 1;
  visibility: visible;
  transition: 1s;
}
}


.menu-close{
  position: absolute;
  top: 0;
  right: 0;
}
@media screen and (min-width: 1000px){
.menu-close{
  display: none;
}
}

.menu-trigger{
  position: relative;
  z-index: 2;
}
@media screen and (min-width: 1000px){
.menu-trigger{
  display: none;
}
}

pc版のスタイルに対して、@media screen and (min-width: 1000px)にてCSSを変更しています。

.nav-menu:not(:target), .nav-menu:target に関してはスマホ版のみのスタイルなので、@media screen and (max-width: 1000px) にて指定してあります。

以上にてレスポンシブ対応が完了しました。
ブレークポイントを増やす場合は、適宜追加してください。

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3