10分でマテリアルデザインのダッシュボードを作る

いま作っているWebサービスでマテリアルデザイン採用することにしました。
マテリアルデザイン用のCSSはたくさんありますが、今回は一番有名そうなMaterializeを使うことにしました。

基本的な使い方は公式のドキュメントを見ればわかるのですが、今回ダッシュボードを作ろうとした時に参考になる記事があまりなさげで詰まったのでここに残します。

この記事に沿って進めていただければ最終的にこんなものが出来上がります。


![materialize0.gif](https://qiita-image-store.s3.amazonaws.com/0/112614/5167d905-7d57-24da-68e8-b42c0916bc83.gif)

ソースはここに置いておきます。
[ソース](https://gist.github.com/DaichiSaito/28e10fcd7eec396b235c3837118ab08e)

以下手順です。
なお、今回はヘッダ情報等々最低限の実装でいきます。またスタイルもスクリプトも全て`index.html`に書くことにします。
#1.雛形を作る

```html:index.html
<html>
<head>

</head>

<body>

</body>
</html>
```

#2.Materializeを読み込む
[Getting Started](https://materializecss.com/getting-started.html)

```html:index.html
<html>
<head>

  <!-- Compiled and minified CSS -->
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0-rc.2/css/materialize.min.css">

  <!-- Compiled and minified JavaScript -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0-rc.2/js/materialize.min.js"></script>

</head>

<body>
</body>
</html>
```

この時点ではまだまっさらです。
次にヘッダーを作っていきます。

#3.ヘッダーナビゲーションを作る
[Navbar](https://materializecss.com/navbar.html)

```html:index.html

<body>

  <header>

    <!-- 追記 -->
    <nav>
      <div class="nav-wrapper">
        <a href="#" class="brand-logo">Logo</a>
        <ul id="nav-mobile" class="right hide-on-med-and-down">
          <li><a href="sass.html">Sass</a></li>
          <li><a href="badges.html">Components</a></li>
          <li><a href="collapsible.html">JavaScript</a></li>
        </ul>
      </div>
    </nav>

  </header>

</body>

```

これだけでレス化されたヘッダーナビゲーションが作れます。


![materialize1.gif](https://qiita-image-store.s3.amazonaws.com/0/112614/2d22bfd4-d6d9-605a-43a8-ba142a03261b.gif)

次にサイドバーを作っていきます。

#4.サイドバーを作る
[Sidenav](https://materializecss.com/sidenav.html)

サイドバーはJavascriptが必要になってきます。Materializeにはサイドバーの他にもドロップダウンやカルーセルなど色々な機能が用意されており、そのそれぞれに初期化用の関数があります。詳しくはドキュメントを参照してください。今回のサイドバーに関して言うとこのように初期化します。

```javascript

  <script>
    document.addEventListener('DOMContentLoaded', function() {
      var elems = document.querySelectorAll('.sidenav');
      var instances = M.Sidenav.init(elems, {});
    });
  </script>
```

また、サイドバーの幅分メインコンテンツ部分にpaddingを取ってやる必要があります。

```html:index.html
    <nav>
      <div class="nav-wrapper">
        <a href="#" class="brand-logo">Logo</a>
        <ul id="nav-mobile" class="right hide-on-med-and-down">
          <li><a href="sass.html">Sass</a></li>
          <li><a href="badges.html">Components</a></li>
          <li><a href="collapsible.html">JavaScript</a></li>
        </ul>
      </div>
    </nav>

    <!-- マークアップ追記 -->
    <ul id="slide-out" class="sidenav sidenav-fixed">
      <li><a href="#!">First Sidebar Link</a></li>
      <li><a href="#!">Second Sidebar Link</a></li>
    </ul>
    <a href="#" data-target="slide-out" class="sidenav-trigger"><i class="material-icons">menu</i></a>


  <!-- スクリプト追記 -->
  <script>
    document.addEventListener('DOMContentLoaded', function() {
      var elems = document.querySelectorAll('.sidenav');
      var instances = M.Sidenav.init(elems, {});
    });
  </script>

  <!-- スタイル追記 -->
  <style>
    header, main, footer {
      padding-left: 300px;
    }

    @media only screen and (max-width : 992px) {
      header, main, footer {
        padding-left: 0;
      }
    }
  </style>

```


**ちょっとハマったのが、サイドバーのul要素のクラスに`sidenav-fixed`を設定しないとサイドバーが表示されなかった点です。**これを付与することで固定化される=初期表示されるということなのでしょう。
ここまででこのようなUIになると思います。
![materialize2.gif](https://qiita-image-store.s3.amazonaws.com/0/112614/4022d9da-a9a8-5862-fac8-a22485f56595.gif)

ただ、これだとハンバーガーがおかしな位置にあるのでそれを直しましょう。

#5.ハンバーガーを正しい位置に表示する

```html:index.html
    <nav>
      <div class="nav-wrapper">
        <a href="#" class="brand-logo">Logo</a>
        <ul id="nav-mobile" class="right hide-on-med-and-down">
          <li><a href="sass.html">Sass</a></li>
          <li><a href="badges.html">Components</a></li>
          <li><a href="collapsible.html">JavaScript</a></li>
        </ul>
        <!-- ここに移動 -->
        <a href="#" data-target="slide-out" class="sidenav-trigger"><i class="material-icons">menu</i></a>
      </div>
    </nav>

    <ul id="slide-out" class="sidenav sidenav-fixed">
      <li><a href="#!">First Sidebar Link</a></li>
      <li><a href="#!">Second Sidebar Link</a></li>
    </ul>
    <!-- ここにあったものを上のほうに移動 -->

```

サイドバー以下にあったものをヘッダーナビゲーションのところに置きました。
これでダッシュボードの大体の形は完成です。

せっかくなのでもう少しかっこよくしてみようと思います。

#6.アイコンをつける
[Icons](https://materializecss.com/icons.html)

FontAwesomeのようなものがMaterializeには用意されいるのでそれを使います。
https://materializecss.com/icons.html

・まずアイコンを使うためにhead内で必要なリソースを読み込みます
・使いたいところで `<i class="material-icons left">person</i>` のように書きます。

```html:index.html

<head>
  <!-- 追記 -->
  <!--Import Google Icon Font-->
  <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">

  <!-- Compiled and minified CSS -->
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0-rc.2/css/materialize.min.css">

  <!-- Compiled and minified JavaScript -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0-rc.2/js/materialize.min.js"></script>
</head>

省略

    <!-- <i>の部分追記 -->
    <ul id="slide-out" class="sidenav sidenav-fixed">
      <li><a href="#!">First Sidebar Link<i class="material-icons left">person</i></a></li>
      <li><a href="#!">Second Sidebar Link<i class="material-icons left">local_post_office</i></a></li>
    </ul>
````

そうするとこのようになると思います。

![スクリーンショット 2018-08-12 20.03.06.png](https://qiita-image-store.s3.amazonaws.com/0/112614/1cba176e-e181-8f0f-df5a-dc669c8b5a52.png)

アイコンがついて少しおしゃれな感じになりました。


#7.アコーディオンメニューを作る
[Collapsible](https://materializecss.com/collapsible.html)

場合によってはメニューをグループ化したいということもあると思います。
Materializeではアコーディオンも簡単に実現できるのでそれを紹介して最後にしようと思います。

```html:index.html
    <ul id="slide-out" class="sidenav sidenav-fixed">
      <li><a href="#!">First Sidebar Link<i class="material-icons left">person</i></a>
      </li>
      <li><a href="#!">Second Sidebar Link<i class="material-icons left">local_post_office</i></a></li>

      <!-- 追加 -->
      <li>
        <ul class="collapsible">
          <li>
            <a class="collapsible-header">Accordion<i class="material-icons chevron right">chevron_left</i></a>
            <div class="collapsible-body">
              <ul>
                <li><a href="#">Dashboard<i class="material-icons">web</i></a></li>
                <li><a href="#">Fixed Chart<i class="material-icons">list</i></a></li>
                <li><a href="#">Grid<i class="material-icons">dashboard</i></a></li>
                <li><a href="#">Chat<i class="material-icons">chat</i></a></li>
              </ul>
            </div>
          </li>
        </ul>
      </li>
    </ul>
```

ポイントは
・`collapsible-header`を付与した要素がアコーディオンの親になる
・`collapsible-body`を付与した要素がアコーディオンの子になる
・それらを`collapsible`というクラスを付与した`ul`の配下に置く
です。

また、`<i class="material-icons chevron right">`をつけてやれば矢印（？）アイコンが表示されるのでよりアコーディオンっぽく見えるようになります。
アコーディオンがアクティブになった時にその矢印アイコンが下に向くように以下のようなスタイルを追記してあげます。

```html:index.html
  <style>
    header, main, footer {
      padding-left: 300px;
    }

    @media only screen and (max-width : 992px) {
      header, main, footer {
        padding-left: 0;
      }
    }

    /* 追加 */
    .sidenav .collapsible>.active .collapsible-header .chevron {
        transform: rotate(-90deg);
    }
  </style>
```

そうすればこのようになるはずです。


![materialize5.gif](https://qiita-image-store.s3.amazonaws.com/0/112614/1c0ca762-3a29-8365-b063-4c36625adde4.gif)

#さいごに
色々と説明してきましたが、結局は公式サイトに書いてあるものの組み合わせでしかないですね。ただ、どれをどう組み合わせたらダッシュボードちっくなUIが実現できるのかがわからないという人も案外いるのではないでしょうか？この記事が少しでもそんな人たちの役に立てればなと思います。

なお、これくらいの実装であればイチから自力で作ることもそこまで負荷ではないのでMateriarizeを使うまででもないと思います。**ただ、Materializeの真髄は細かいアニメーションにあると思っていて**、例えばタップした時のちょっとした波のようなアニメーションなんか自分で実装するとしても大変ですが、Materializeを使えば`waves-effect`というクラスを付与するだけで実現できたりします。また、ポップアップのアニメーションも簡単に実現できます。

参考(gifだとわかりづらい...)
[https://themes.materializecss.com/pages/admin-fixed-chart](https://themes.materializecss.com/pages/admin-fixed-chart)
![materialize6.gif](https://qiita-image-store.s3.amazonaws.com/0/112614/f6571b22-35e8-d529-b1e2-aeafddd88f09.gif)

個人的に`float`を使っているところだけ残念ですが、それを差し引いても使う価値のあるCSSフレームワークだと思いました。