CSSとJSでメニューボタンを作る

#概要
スマートフォン向けのWebページによくあるアレを実装します。
三本線のボタンを押すと候補が現れ、押すとリンク先に移動します。
詳細は以下の通りです。

- 状態A（初期状態）
 - 三本線のボタンのみ表示
 - 三本線のボタンをクリック --> 状態B

- 状態B
 - バツのボタンと移動先（リンク）の表を表示
 - バツのボタンをクリック --> 状態A に戻る
 - いずれかのリンクをクリック --> リンク先に移動、状態A に戻る

#ソースコード
ソースコードです。（説明は後述）

- HTML

```html:test1.html
﻿<!DOCTYPE html>
<!-- test1.html -->
<html lang="ja">
  <head>
    <title>test1</title>
    
    <!-- 三本線は Font Awesome を使いました。自作してもいいかもしれません。 -->
    <link href="https://use.fontawesome.com/releases/v5.0.6/css/all.css" rel="stylesheet">
    
    <!-- CSSやJSファイルを別フォルダに入れている場合は適宜読み替えてください。 -->
    <!-- CSS -->
    <link rel="stylesheet" href="test.css">
    <!-- JavaScript -->
    <script type="text/javascript" src="test.js"></script>

  </head>
  <body>
  
    <!-- メニューボタン等ここから -->
    <div id="menubutton">
      <div id="menubutton_wrap" onclick="menulist_appear()">
        <div id="menubutton_icon">
          <p>
            <i class="fas fa-bars"></i>
          </p>
        </div>
      </div>
    </div>
    <div id="closebutton"></div>
    <div id="menulist"></div>
    <!-- メニューボタン等ここまで -->
    
    <!-- あとは好きなように書く -->

    <article>
      <h1>test1</h1>
    </article>
  </body>
</html>
```
ソースコード中の `test1` を `test2` に変えた test2.html も用意してください。

- JavaScript

```javascript:test.js
// test.js

function menulist_appear()
{
  closebutton = '<div id="closebutton_wrap" onclick="menulist_disappear()"><div id="closebutton_icon"><p><i class="fas fa-times"></i></p></div></div>';

  menulist = '';
  menulist += '<table>';
    menulist += '<tr><td><a href="test1.html" onclick="menulist_disappear()"><span class="linktext">test1</span></a></td></tr>';
    menulist += '<tr><td><a href="test2.html" onclick="menulist_disappear()"><span class="linktext">test2</span></a></td></tr>';
  menulist += '</table>';

  document.getElementById("menubutton").innerHTML = '';
  document.getElementById("closebutton").innerHTML = closebutton;
  document.getElementById("menulist").innerHTML = menulist;
};

function menulist_disappear()
{
  menubutton = '<div id="menubutton_wrap" onclick="menulist_appear()"><div id="menubutton_icon"><p><i class="fas fa-bars"></i></p></div></div>';
  document.getElementById("menubutton").innerHTML = menubutton;
  document.getElementById("closebutton").innerHTML = '';
  document.getElementById("menulist").innerHTML = '';
};
```

- CSS

```css:test.css
/* test.css */

:root{
  --color-text-default: #333;
  --color-text-active: #fff;
  --color-bg: #ddd;
  --color-border: #aaa;
}

#menubutton, #closebutton, #menulist {
  text-align: center;
  font-family: sans-serif;
}

#menubutton_wrap, #closebutton_wrap {
  z-index: 3;
  position: fixed;
  top: 20px;
  right: 20px;
  width: 50px;
  height: 50px;
  color: var(--color-text-default);
  background-color: var(--color-bg);
  border: solid 2px var(--color-border);
  border-radius: 50%;
}

#menubutton_wrap:hover, #menubutton_wrap:active, #closebutton_wrap:hover, #closebutton_wrap:active {color: var(--color-text-active);}

#menubutton_icon, #closebutton_icon {
  position: relative;
  top: -6px;
  left: 0px;
  font-size: 16pt;
}

#menulist{
  z-index: 3;
  position: fixed;
  top: 80px;
  right: 10px;
  background: var(--color-bg);
  font-size: 16pt;
  margin: 0;
  padding: 0;
}

#menulist table {border-collapse: collapse;}

#menulist td {border: solid 2px var(--color-border);}

#menulist a {
  display: block;
  padding: 4px 0;
  text-decoration: none;
  color: var(--color-text-default);
}

.linktext {padding: 0 4px;}

#menulist a:active, #menulist a:hover {color: var(--color-text-active);}
```

#解説

以下、ソースコードの説明です。

##HTML

3つの div を用意します。（`<div id="#xxx">...</div>`）

- `#menubutton`: 三本線のボタン用

```html
<div id="menubutton">
  <div id="menubutton_wrap" onclick="menulist_appear()">
    <div id="menubutton_icon">
      <p>
        <i class="fas fa-bars"></i>
      </p>
    </div>
  </div>
</div>
```
`<i class="fas fa-bars"></i>` は Font Awesome の三本線のアイコンです。

- `#closebutton`: バツのボタン用
 
```html
<div id="closebutton">
  <div id="closebutton_wrap" onclick="menulist_disappear()">
    <div id="closebutton_icon">
      <p>
        <i class="fas fa-times"></i>
      </p>
    </div>
  </div>
</div>
```
`<i class="fas fa-times"></i>` は Font Awesome のバツのアイコンです。

- `#menulist`: リンクの表用

```html
<div id="menulist">
  <table>
    <!-- リンクを好きなだけ並べる -->
    <tr>
      <td>
        <a href="test1.html" onclick="menulist_disappear()">
          <span class="linktext">test1</span>
        </a>
      </td>
    </tr>
    <tr>
      <td>
        <a href="test2.html" onclick="menulist_disappear()">
          <span class="linktext">test2</span>
        </a>
      </td>
    </tr>
  </table>
</div>
```
今回は別ページへのリンクを張っていますが、同一ページ内のリンクでも構いません。

これらのうち、`#menubutton` 以外はデフォルトでは表示しないので、HTML ファイルには

```html
<div id="menubutton">
...
</div>
<div id="closebutton"></div> (空)
<div id="menulist"></div> (空)
```
と書いてあります。

##JavaScript

ボタンがクリックされた時の動作を記述します。

- `menulist_appear`:
二つの div `#closebutton`, `#menulist` の中にはもともと何も書かれていません。
三本線のアイコンが表示されている時にボタンをクリックするとこの関数が呼び出さます。
HTML コードが挿入され、バツのボタンとリンクの表が出現します。
また、`#menubutton` の中身が消えて、三本線のボタンが表示されなくなります。

```html
<div id="menubutton"></div> (空)
<div id="closebutton">...</div>
<div id="menulist">...</div>
```

- `menulist_disappear`:
バツのアイコンが表示されている時にボタンやいずれかのリンクをクリックするとこの関数が呼び出されます。
三本線のボタンが現れ、バツのボタンとリンクの表が消えます。

```html
<div id="menubutton">...</div>
<div id="closebutton"></div> (空)
<div id="menulist"></div> (空)
```

##CSS

ボタンの配置や色を決めます。
HTML だけだとアイコンやリンクの文字が表示されるだけですが、位置を指定し、枠や背景の色を変えることで初めてボタンのように見えます。

まず、色を定義します。（本記事の例では、分かりやすいように全て異なる色にしていますので、お好みで調整してください。）[^color]

[^color]: 色は `#aaa` だけでなく `red` や `#ff0000` 等でも指定できます。

```css
:root{
  --color-text-default: #333;  /* アイコンや文字の色（通常時） */
  --color-text-active: #fff;  /* アイコンや文字の色（マウスオーバー時） */
  --color-bg: #ddd;  /* ボタンの背景色 */
  --color-border: #aaa;  /* ボタンの枠の色 */
}
```
**注意**
変数は先頭にハイフンを2つ付けて定義します (`--xxx`).
これらの変数は `var(--xxx)` でアクセスできます。

共通の設定です。

```css
#menubutton, #closebutton, #menulist {
  text-align: center;
  font-family: sans-serif;
}
```

###メニューボタン

配置と色を指定します。
画面右上にボタンを表示させる場合、位置を `top` と `right` で指定します。

```css
#menubutton_wrap, #closebutton_wrap {
  z-index: 3;
  position: fixed;  /* 重要 */
  top: 20px;  /* 画面上側に配置する場合 */
  right: 20px;  /* 画面右側に配置する場合 */
  width: 50px;
  height: 50px; /* width = height となるように指定してください。 */
  color: var(--color-text-default);
  background-color: var(--color-bg);
  border: solid 2px var(--color-border);
  border-radius: 50%;  /* 四角い枠の角を丸くすることでボタンの円を作ります。 */
}
```

上記 `border: solid 2px var(--color-border);` は分けて書くと以下の通りです。

```css
border-width: 2px;  /* 枠の太さ */
border-style: solid;  /* 枠のスタイル（一本線） */
border-color: var(--color-border);
```

ボタン上にカーソルがある時は、アイコンの色を変えます。

```css
#menubutton_wrap:hover, #menubutton_wrap:active, 
#closebutton_wrap:hover, #closebutton_wrap:active {
  color: var(--color-text-active);
}
```

ボタン内での三本線とバツのアイコンの位置を指定します。

```css
#menubutton_icon, #closebutton_icon {
  position: relative;  /* 重要 */
  top: -6px;  /* 縦位置はここで適宜調整してください。 */
  left: 0px; /* 中央揃えにしてあるのでこちらは変える必要ありません。 */
  font-size: 16pt;  /* アイコンの大きさ */
}
```

###リンクの表

配置と色を指定します。
メニューボタンの直下に表示されるように値を決める必要があります。

```css
#menulist{
  z-index: 3;
  position: fixed;
  top: 80px;  /* 画面上側に配置する場合 */
  right: 10px;  /* 画面右側に配置する場合 */
  background: var(--color-bg);
  font-size: 16pt;
  margin: 0;
  padding: 0;
}
```

表の見た目を指定します。

```css
#menulist table {
  border-collapse: collapse;  /* border を重ねて表示 */
}

#menulist td {
  border: solid 2px var(--color-border);
}
```

リンクテキストの設定をします。

```css
#menulist a {
  display: block;
  padding: 4px 0;  /* 上下の padding */
  text-decoration: none;  /* リンクテキストの下線を消す */
  color: var(--color-text-default);
}

.linktext {
  padding: 0 4px;  /* 左右の padding */
}
```
各セルの大きさは、リンクテキストの幅・高さ[^linkfontsize]に応じて自動的に決まりますが、`padding` を指定することで大きくすることができます。（値が2つの場合、`padding: [上下] [左右];` です。）
文字ギリギリに枠があると窮屈に見えるので、設定することをおすすめします。
`<a>` タグはインライン要素ですが、`display: block;` と指定するとブロック要素として扱われるようになります。
こうすることで、表のセル全体にリンクを拡げることができます。[^displayblock]

[^linkfontsize]: リンクテキストの文字の大きさは、`#menulist` の `font-size` で指定します。

[^displayblock]: そのままだとリンクテキスト上でクリックしたときしか移動できません。

各リンクのボタン上にカーソルがある時は、文字の色を変えます。

```css
#menulist a:active, #menulist a:hover {
  color: var(--color-text-active);
}
```

これで出来上がりです。