JavaScriptを使ったドロワーメニューの作り方について解説!

こんにちは!キャメルです!

今回はドロワーメニューの作り方について解説をしていきます!

ドロワーメニューってなんだっけ…?

ドロワーメニューというのはアイコンなどをクリックすると出現するメニューのことです。

こんなやつ。

ドロワーメニュー

スマホなどのレスポンシブウェブデザインでよく使うものになるので、必ず作れるようになっておきましょう。

一つひとつ丁寧に解説していきますので、ぜひ最後まで読んでくださいね^^

今回の記事でできるようになること
  • ドロワーメニューについて理解できる
  • 実際にドロワーメニューを作れるようになる
目次

ドロワーメニューとは?

まずは簡単にドロワーメニューについて説明をします。

ドロワーメニューは、アイコンをクリックすることにより画面に表示されるナビゲーションメニューのことです。

代表的なアイコンとしてはハンバーガーアイコンなどがよく見られますね!3本線のこんなアイコンです^^

皆さんもスマホでショッピングをするときなどに見たことがありますよね^^

ハンバーガーメニュー

このハンバーガーアイコンをタップしたりクリックしたりすると下の画像のようにメニューが出現します。

drawerは英語で「引き出し」という意味。引き出しのようにスライドしてきて表示されるためこのような名前になっているみたいです。

ドロワーメニュー

具体的にはどんな場面で使うの?

スマートフォンやタブレットなどの画面が小さいデバイスで使うことが多いんだ。

パソコンと比べてスマホやタブレットは表示領域が狭く、表示できるボタンや文字数も限られてきます。

そのため、普段は非表示にして隠しておけるドロワーメニューはとても便利な機能になります。

ドロワーメニューのメリットとデメリット

ドロワーメニューのメリットとデメリットについてもいくつか解説をします。

特にデメリットを知らないと、ユーザーにとって使いにくいサイトを作ってしまうことになりかねないのでしっかり認識しておきましょう!

ドロワーメニューのメリット

ドロワーメニューのメリットとしては次のようなものが挙げられます。

スペースを有効活用できる

ドロワーメニューは普段は非表示になっているため、画面のスペースを有効活用することができます。

特にスマホやタブレットなどの限られたスペースしかない場合にはとても便利な機能になります。

直感的に使いやすい

アイコンをクリックするだけでメニューを開けるため、操作がシンプルで簡単です。

特にハンバーガーアイコンなどはよく使われるものなので、「あ、これ押せばメニューが出てくるんだな」と直感的に伝わりやすく使いやすいです。

アニメーション効果

スライドイン・スライドアウトなどのアニメーション効果によりユーザーにとって視覚的な親しみやすさもあります。

ドロワーメニューのデメリット

デメリットとしては以下のようなものがあります。

アクセシビリティが低下する可能性がある

キーボードで操作しているユーザーなどが使いにくくなる可能性があるため、tabキーでフォーカスが当たるようにするなどの配慮が必要です。

ユーザビリティが低下する可能性がある

アニメーションの速度が遅いとメニューを開くのに時間がかかりユーザビリティの低下を招く可能性があります。

アニメーションの動作時間を短く設定したり、シンプルなアニメーションにするなどの工夫が必要となります。

メニュー項目が多いときには不向き

表示領域が狭いため、メニュー項目が複雑な場合や多すぎる場合には不向きなことがあります。

ドロワーメニューの作り方

それではここからドロワーメニューの作り方について具体的に解説をしていきます!

あくまでドロワーの基本的な作り方について解説をすることが目的なので、ヘッダーやメニュー構造はシンプルな構成にしています。

参考コードはこちら。

-- HTML --

<header class="header">
    <div class="header__inner">
      <h1 class="header__logo">ごーいんぐブログ</h1>
      <nav class="header__nav">
        <ul class="header__lists">
          <li class="header__list"><a href="">事業内容</a></li>
          <li class="header__list"><a href="">お知らせ</a></li>
          <li class="header__list"><a href="">ブログ</a></li>
          <li class="header__list"><a href="">お問い合わせ</a></li>
        </ul>
      </nav>
      <button class="header__drawer drawer-icon" id="js-drawer-icon">
        <span></span>
        <span></span>
        <span></span>
      </button>
    </div>
  </header>

<!-- ドロワーメニューは別ブロックで作っておく -->
  <div class="drawer-content" id="js-drawer-content">
    <nav class="drawer-content__menu">
      <ul class="drawer-content__lists">
        <li class="drawer-content__list"><a href="">事業内容</a></li>
        <li class="drawer-content__list"><a href="">お知らせ</a></li>
        <li class="drawer-content__list"><a href="">ブログ</a></li>
        <li class="drawer-content__list"><a href="">お問い合わせ</a></li>
      </ul>  
    </nav>
  </div>
-- CSS --

.header {
  display: block;
  width: 100%;
  max-width: 100%;
  background-color: #65AF36;
}
.header__inner {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 50px 20px;
}
.header__logo {
  color: #fff;
}
.drawer-icon {
  position: relative;
  width: 30px;
  height: 16px;
  z-index: 101;
}
.drawer-icon span {
  display: block;
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 4px;
  background-color: #fff;
  transition: transform 0.3s linear, top 0.3s linear, opacity 0.3s linear;
}
.drawer-icon span:nth-child(2) {
  top: 8px;
}
.drawer-icon span:nth-child(3) {
  top: 16px;
}
.drawer-icon.is-checked span:nth-child(1) {
  top: 8px;
  transform: rotate(45deg);
}
.drawer-icon.is-checked span:nth-child(2) {
  opacity: 0;
}
.drawer-icon.is-checked span:nth-child(3) {
  top: 8px;
  transform: rotate(-45deg);
}
.header__nav {
  display: none;
}
.header__lists {
  display: flex;
  justify-content: center;
}
.header__list {
  list-style: none;
}
.header__list a {
  display: block;
  color: #fff;
  padding: 5px 20px;
}
.header__list a:hover {
  opacity: 0.8;
}
.drawer-content {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  width: 100%;
  height: 100%;
  padding: 80px 20px;
  background-color: #65AF36;
  z-index: 100;
  transform: translateX(101%);
  transition: transform 0.8s ease;
}
.drawer-content.is-checked {
  transform: translateX(0);
}
.drawer-content__menu {
  width: 80%;
  height: 60%;
  position: fixed;
  inset: 0;
  margin: auto;
  padding: 20px;
  background-color: #fff;
}
.drawer-content__lists {
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.drawer-content__list {
  text-align: center;
}
.drawer-content__list a {
  display: block;
  color: #000;
  padding: 20px 0;
}

@media screen and (min-width: 768px) {
  .header__inner {
    max-width: 1240px;
    margin-inline: auto;
  }
  .header__drawer {
    display: none;
  }
  .header__nav {
    display: block;
  }
  .drawer-content {
    display: none;
  }
}
-- JavaScript --

const drawerIcon =  document.querySelector('#js-drawer-icon');
const drawerContent =  document.querySelector('#js-drawer-content');  
if(drawerIcon) {    
  drawerIcon.addEventListener('click', (e)=> {
   e.preventDefault();
   drawerIcon.classList.toggle('is-checked');
   drawerContent.classList.toggle('is-checked');
  });    
}

1. ドロワーメニューの形を作る

HTML

まずはHTMLから見ていきましょう!

-- HTML --

<header class="header">
    <div class="header__inner">
      <h1 class="header__logo">ごーいんぐブログ</h1>
      <nav class="header__nav">
        <ul class="header__lists">
          <li class="header__list"><a href="">事業内容</a></li>
          <li class="header__list"><a href="">お知らせ</a></li>
          <li class="header__list"><a href="">ブログ</a></li>
          <li class="header__list"><a href="">お問い合わせ</a></li>
        </ul>
      </nav>
      <button class="header__drawer drawer-icon" id="js-drawer-icon">
        <span></span>
        <span></span>
        <span></span>
      </button>
    </div>
  </header>

<!-- ドロワーメニューは別ブロックで作っておく -->
  <div class="drawer-content" id="js-drawer-content">
    <nav class="drawer-content__menu">
      <ul class="drawer-content__lists">
        <li class="drawer-content__list"><a href="">事業内容</a></li>
        <li class="drawer-content__list"><a href="">お知らせ</a></li>
        <li class="drawer-content__list"><a href="">ブログ</a></li>
        <li class="drawer-content__list"><a href="">お問い合わせ</a></li>
      </ul>  
    </nav>
  </div>
ポイントはここ!
  • ヘッダー部分とドロワーメニューの本体は分けて記述する

ちなみに今回のHTMLのクラスの命名はBEMを使っているので、ぜひBEMについても復習だと思って振り返りながらやってみてくださいね^^

BEMについてはこちらの記事も参考にしてみてくださいねっ!

今回はドロワーに関するコード(参考コードの赤字部分)を中心に解説をしていきますね!

<h1 class="header__logo">ごーいんぐブログ</h1>

まずは<h1>タグの部分。ここは今回の主旨とは外れますが、本来はその会社のロゴを画像として入れることが多いです。

<button class="header__drawer drawer-icon" id="js-drawer-icon">
  <span></span>
  <span></span>
  <span></span>
</button>

次にハンバーガーアイコンを作っていきます。

ここで<button>タグを使っているのは、tabキーでフォーカスが当たるようにするためです。前述したようにアクセシビリティを考慮した設計を心がけましょう。

3本の線をそれぞれ<span>タグで作り、CSSで線の長さや太さを調整していきます。

ヘッダー部分はこれで完了です^^

続いてドロワーメニューの本体部分を作っていきましょう!

<div class="drawer-content" id="js-drawer-content">    
  <nav class="drawer-content__menu">
    <ul class="drawer-content__lists">
      <li class="drawer-content__list"><a href="">事業内容</a></li>
      <li class="drawer-content__list"><a href="">お知らせ</a></li>
      <li class="drawer-content__list"><a href="">ブログ</a></li>
      <li class="drawer-content__list"><a href="">お問い合わせ</a></li>
    </ul>
  </nav>
</div>
<div class="drawer-content" id="js-drawer-content">    

HTMLについてはそれほど特徴的な部分はなく、通常のグローバルメニューと同様に作っていきます。

JavaScriptで操作をする部分については「js-」という接頭辞をつけてid属性として指定することが多いです。

ここはjsで操作をしているよ〜

ということを伝えるためですね。

CSS

続いて、CSSで見た目を調整していきます。

今回はスマホファーストでスタイルを当てていきましょう^^

スマホファーストとは?

パソコンよりもスマホのデザインを先に作っていくことをスマホファーストと呼びます。
従来はパソコンのデザインを作ってからスマホにデザインを当てていくのが普通でしたが、最近はスマホが普及したことでスマホでの使用を最優先に考えてデザインを当てていくことが増えています。

CSSの参考コードはこちら!赤字の部分を中心に解説をしていきます!

-- CSS --

.header {
  display: block;
  width: 100%;
  max-width: 100%;
  background-color: #65AF36;
}
.header__inner {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 50px 20px;
}
.header__logo {
  color: #fff;
}
.drawer-icon {
  position: relative;
  width: 30px;
  height: 16px;
  z-index: 101;
}
.drawer-icon span {
  display: block;
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 4px;
  background-color: #fff;
  transition: transform 0.3s linear, top 0.3s linear, opacity 0.3s linear;
}
.drawer-icon span:nth-child(2) {
  top: 8px;
}
.drawer-icon span:nth-child(3) {
  top: 16px;
}
.drawer-icon.is-checked span:nth-child(1) {
  top: 8px;
  transform: rotate(45deg);
}
.drawer-icon.is-checked span:nth-child(2) {
  opacity: 0;
}
.drawer-icon.is-checked span:nth-child(3) {
  top: 8px;
  transform: rotate(-45deg);
}
.header__nav {
  display: none;
}
.header__lists {
  display: flex;
  justify-content: center;
}
.header__list {
  list-style: none;
}
.header__list a {
  display: block;
  color: #fff;
  padding: 5px 20px;
}
.header__list a:hover {
  opacity: 0.8;
}
.drawer-content {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  width: 100%;
  height: 100%;
  padding: 80px 20px;
  background-color: #65AF36;
  z-index: 100;
  transform: translateX(101%);
  transition: transform 0.8s ease;
}
.drawer-content.is-checked {
  transform: translateX(0);
}
.drawer-content__menu {
  width: 80%;
  height: 60%;
  position: fixed;
  inset: 0;
  margin: auto;
  padding: 20px;
  background-color: #fff;
}
.drawer-content__lists {
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.drawer-content__list {
  text-align: center;
}
.drawer-content__list a {
  display: block;
  color: #000;
  padding: 20px 0;
}

@media screen and (min-width: 768px) {
  .header__inner {
    max-width: 1240px;
    margin-inline: auto;
  }
  .header__drawer {
    display: none;
  }
  .header__nav {
    display: block;
  }
  .drawer-content {
    display: none;
  }
}

まずはハンバーガーアイコンにスタイルを当てていきましょう。

-- CSS --

.drawer-icon {
  position: relative;
  width: 30px;
  height: 16px;
  z-index: 101;
}

まずはアイコン自体の大きさを決めます。今回は高さを16pxと設定しました。

-- CSS --

.drawer-icon span {
  display: block;
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 4px;
  background-color: #fff;
  transition: transform 0.3s linear, top 0.3s linear, opacity 0.3s linear;
}
.drawer-icon span:nth-child(2) {
  top: 8px;
}
.drawer-icon span:nth-child(3) {
  top: 16px;
}

上記コードではハンバーガーアイコンを形成する3本のラインを作り、それぞれの配置を決めています。

先ほどアイコン全体の高さを16pxとしたので、1本のラインの高さを4pxにしてちょうど均等に配置されるように位置を指定しています。

-- CSS --

.drawer-icon.is-checked span:nth-child(1) {
  top: 8px;
  transform: rotate(45deg);
}
.drawer-icon.is-checked span:nth-child(2) {
  opacity: 0;
}
.drawer-icon.is-checked span:nth-child(3) {
  top: 8px;
  transform: rotate(-45deg);
}

ここでは .is-checkedがついたときにスタイルを変更しています。

何をしているかというと、

  • .is-checkedが付いたとき(アイコンをクリックしたとき)に、2本目のラインをopacityで消す
  • .is-checkedが付いたとき(アイコンをクリックしたとき)に、1本目と3本目のラインを回転させてバツにする

こんな感じ。

ドロワーメニュー

「.is-checked」は後でJavaScriptを使い付与していきます。

ここまででハンバーガーアイコンが作れました^^

続きを見ていきましょう!

-- CSS --

.header__nav {
  display: none;
}

まず .header__nav はスマホ時には必要ないので消しておきます。

-- CSS --

.drawer-content {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  width: 100%;
  height: 100%;
  padding: 80px 20px;
  background-color: #65AF36;
  z-index: 100;
  transform: translateX(101%);
  transition: transform 0.8s ease;
}
.drawer-content.is-checked {
  transform: translateX(0);
}

ドロワー本体については普段は非表示にしておきたいので、transformで表示画面の外側に追い出しておきます。

transitionを使ってドロワー開閉時のアニメーションを設定します。

-- CSS --

.drawer-content.is-checked {
  transform: translateX(0);
}

そしてハンバーガーアイコンをバツにしたときと同様に .is-checked が付いたときのスタイルを当てていきます

  • .is-checkedが付いたとき(アイコンをクリックしたとき)に、translateXを0に指定してドロワーを表示させる

最後にメディアクエリを使ってパソコン時のスタイルを作っていきます。

-- CSS --

@media screen and (min-width: 768px) {
  .header__inner {
    max-width: 1240px;
    margin-inline: auto;
  }
  .header__drawer {
    display: none;
  }
  .header__nav {
    display: block;
  }
  .drawer-content {
    display: none;
  }
}
  • スマホ時に非表示にしていたグローバルメニューを表示させる
  • ハンバーガーアイコンを非表示にする
  • ドロワーを非表示にする

さぁこれでCSSまでが終わりました!

あとはJavaScriptだけです。あと少し頑張りましょう!

2. ドロワーメニューの動きを実装

JavaScript

モーダルウィンドウの記事でもjsについて詳しく解説をしています。
一緒に学ぶとjsの理解が進むと思うのでぜひ読んでみてくださいね^^

jsのコードはこちら。

-- JavaScript --

const drawerIcon =  document.querySelector('#js-drawer-icon');
const drawerContent =  document.querySelector('#js-drawer-content');  
if(drawerIcon) {    
  drawerIcon.addEventListener('click', (e)=> {
   e.preventDefault();
   drawerIcon.classList.toggle('is-checked');
   drawerContent.classList.toggle('is-checked');
  });    
}

最初から解説していきます。

-- JavaScript --

const drawerIcon =  document.querySelector('#js-drawer-icon');
const drawerContent =  document.querySelector('#js-drawer-content');  

まずはこの部分。何をしているかというと

  • 定数(任意の名前でOK)drawerIconに js-drawer-icon IDを持つ要素を代入する
  • 定数drawerContentに js-drawer-content IDを持つ要素を代入する

目的の要素を取得できているか確認してみましょう!

以下のコードを打ち込んでみてください。

-- JavaScript --

console.log(drawerIcon);
console.log(drawerContent);

そしてデベロッパーツールを開いてコンソールタブを見てみると

デベロッパーツールのコンソールタブ

ちゃんと目的の要素が取得できていることがわかるね

最後です!以下のコードを解説します。

-- JavaScript --
 
if(drawerIcon) {    
  drawerIcon.addEventListener('click', (e)=> {
    e.preventDefault();
    drawerIcon.classList.toggle('is-checked');
    drawerContent.classList.toggle('is-checked');
  });    
}

drawerIcon(ハンバーガーアイコン)をクリックしたときに以下の挙動が起こるように設定しています。

  • drawerIcon(ハンバーガーアイコン)に .is-checked の付け外しをする
  • drawerContent(ドロワー)に .is-checked の付け外しをする

classList.toggleを使って .is-checked の付け外しをしています。

ハンバーガーアイコンをクリックするたびに .is-checked が付いたり外れたりを交互に繰り返ります。

それによってドロワーが開いたり閉じたりするといったロジックです。

以上です!

まとめ:基礎を理解してドロワーメニューを作れるようになろう

いかがでしたでしょうか。

今回の記事ではドロワーメニューについて解説をしました。

今回の記事で解説したこと
  • ドロワーメニューとは何か
  • ドロワーメニューのメリットとデメリットについて
  • ドロワーメニューの作り方について

最近ではスマホなどの小さな端末も普及し、ドロワーメニューは必須アイテムと言えます。

今回の記事を読んで基本が理解できたら、ぜひ実際に手を動かして作ってみましょう!

自分で作ることで理解が深まります。

これを機会にぜひドロワーメニューの作り方についてマスターしておきましょう^^

今回は以上です!それではまた次の記事で!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次