【デザイン音痴の救世主】Material-UIビギナーズガイド

「自分はデザインセンスが無い。だから、サーバーサイドエンジニアとして生きていこう...」
なんて思ったことはありませんか？
選択肢を狭めてしまっていないでしょうか？

もしもそうなのだとしたら、そんなあなたに朗報です！
今日は誰でも簡単にプロデザイナーになれる！？
デザイン音痴の救世主『Material-UI』の使い方をビギナー向けに紹介します。

そして、私自身、実務で約1年半ほどMaterial-UIを使った開発経験があるので
より実践的な使用例も織り交ぜながら説明していきたいと思います。

## Material-UIとは
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490439/d92cb06f-4514-f5fd-ce5d-baca6d8dad92.png)
Googleの『Material Design』をベースに開発されたライブラリです。

『Material Design』はGoogleが提唱したデザインの**ガイドライン**で
「こういう風な見た目にしたら直感的でおしゃれだよ」
という"ルール"みたいな感じのものです。

文字サイズ、余白の幅等々もピクセル単位で細かく定義されており
この『Material Design』のガイドラインに沿って作れば誰でも良い感じの
アプリケーションが作れるようになっています。

名前が少しややこしいですが、『Material-UI』は『Material Design』のガイドラインに沿って開発された**Reactコンポーネントのライブラリ**なのです。

また、Material-UIは初めて使う人にも非常に親切で、誰でも簡単に不安なく使えるよう、サイト内には**デモ**と**サンプルコード**がたくさん用意されています。

「なんだかまだよくわからない」という人のために料理で例えると
Material-UIは**レトルト食品**に似ています。
味付けは既に完成されていて、あとは具材と混ぜるだけ。
調味料の量もグラム単位で管理されていて、「これを使えば誰でも美味しい料理が簡単につくれるよ」
「つくり方はパッケージの裏に書いてあるよ。料理が苦手でもおまかせあれ」といった感じです。

どうでしょう、なんとなくイメージがつきましたか？
要は、「デザインが苦手でもMaterial-UIに任せておけば良い感じになるよ」ということです。

まだわからん、もっと詳しく知りたいという方は公式ドキュメントを参考にしてみてください。

[Material-UI公式](https://material-ui.com/components/cards/#complex-interaction)

## 社内決裁で救われる
Material-UIを導入すると社内決裁時に救われます。

デザインを上司に提案しに行く時、納得してもらう材料を用意するのって大変じゃないですか？
デザインって「これが正解だ」っていう答えがないものなので。
現代文の試験問題でよく見る「この時の作者の心情を答えよ」ぐらい難問ですよね。

提案後に「なんでこのデザインにしたの？」
って質問された時、みなさんは何て答えていますか？

恐らく
「一歩先を見据えた先進的なデザインを考慮し...」や
「モバイル端末のベゼルレス可に伴い...」や
「片手操作の親指のホームポジションの統計を元に...」
といったような理由を頑張ってみつけて説明、説得する場合がほとんどではないでしょうか。

ITリテラシーのある上司であれば上記の説明でも上手く納得してもらえるかもしれませんが
そうでない方の場合、上記のアプローチ方法では上手く理解してもらえないケースもあります。

そんな時に、Material-UIを導入していると以下のセリフを使って説得することができるようになります。

**「Googleが考えたデザインだから」**

「なんでこのデザインにしたの？」という問いに対してのこの回答。
実に単純明快ですね。
ITの知識がなくても、Googleがなんかすごいっぽいっていうのはなんとなく理解している人が多いはずなので、これで百戦錬磨間違いなしです。

なお、Material-UIは『Amazon』、『Netflix』、『NASA』でも使用されているようなので
「『Amazon』、『Netflix』、そしてあの『NASA』でも使われているデザインですよ？」
と言い放てば、上司にはもう反論の余地は残されていないことでしょう。

料理で例えるなら
「このメニューに載っている中華料理が美味しいと思う根拠を教えて？」と上司に聞かれた場合
「『陳建一』が作った中華料理だからです」と説けば
「ああ、それなら美味しいに決まっているな」と上司は納得するはずです。

つまり、Material-UIを導入していると「Googleが考えたデザインなら良いに決まっているな」というセリフを上司から引き出すことができるようになり、社内決裁がスムーズに進むのです。
（これは冗談です）


## 基本編
いままでの内容で、Material-UIの素晴らしさを理解していただけたと思うので、ここから本題です。
基本的な使い方をお教えします。

といっても難しいことは一切なく、以下の手順を行うだけです。

1. [Material-UI公式](https://material-ui.com/components/box/)を開く

2. 左に表示されたメニューから導入したいコンポーネントを探す（今回はButtonを選択）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490439/98da9257-6f88-cf00-9647-9f375eafdf02.png)

3. < > ← このマークをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490439/836db8cd-cb2b-a01b-470d-473bdb8ad008.png)

4. サイトのソースコードをコピーして自分の作成したjsx(またはtsx)ファイルに貼り付けたら完了です
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490439/dde200fd-9f99-7348-e2fc-32d724b62b7a.png)

簡単ですね。

※実務で使用する際はただコピペするだけではなく、コードの中身を理解した上で使用してくださいね

## スタイルの適用編
また、Material-UIには『**Styles**』というCSS-in-JSを実現する便利なパッケージが含まれています。

#### CSS-in-JSとは？
まず、Reactにスタイルを適用させる記法として以下4つの代表的な方法があります。

1. CSS-in-JS
2. CSS-Module
3. inline-style
4. className

それぞれにメリットとデメリットがあり、どの方法を採用するのかはプロダクトチームと相談して決めるべきだと思いますが、私がおすすめするのは『CSS-in-JS』です。

CSS-in-JSはこんな感じ↓で書きます。

```JavaScript
import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';

const useStyles = makeStyles({
  root: {
    background: 'linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)',
    border: 0,
    borderRadius: 3,
    boxShadow: '0 3px 5px 2px rgba(255, 105, 135, .3)',
    color: 'white',
    height: 48,
    padding: '0 30px',
  },
});

export default function Hook() {
  const classes = useStyles();
  return <Button className={classes.root}>Hook</Button>;
}
```

CSS-in-JSはその名の通り、JSファイルの中にCSSも合わせて記述する方式です。
Reactはコンポーネント指向のライブラリなので、各コンポーネントごとにファイル分割をして開発するのが一般的ですよね。

そのため、特定のコンポーネントに適用したいスタイルを、コンポーネントのファイルの中に一緒に記述するCSS-in-JS記法であれば、管理がよりしやすくなると感じているため、私は数あるCSS記法の中で、特にCSS-in-JSを推しています。

加えて、ただでさえReactはファイル数が多くなりがちでファイル管理が大変なのに、スタイル部分を別ファイルに切り出して管理しようとすると、さらにファイルが増えてファイルの移動が面倒になりがちですから。

上記コードの解説をちょっとだけしますと

```JavaScript
import { makeStyles } from '@material-ui/core/styles';
```

↑この『makeStyles』というのがMaterial-UIのスタイル機能の本体で

```JavaScript
const useStyles = makeStyles({
  root: {
    color: 'white',
  },
});
```

↑こんな感じでクラス名（この例の場合『root』がクラス名）と適用したいスタイル属性を定義し

```JavaScript
const classes = useStyles();
return (
  <Button className={classes.root}>
    {'ボタン'}
  </Button>
)
```

↑こんな感じで適用させます

料理で例えると
通常のClassNameで指定する方法は**"茶碗にはご飯が盛られ、丸皿にはおかずが盛られている"**感じですが
CSS-in-JSは**"1枚のプレートにご飯もおかずも合わせて盛られている"**みたいな感じです。
一枚のお皿に全部盛られている方が洗い物も少なくて済みますし、持ち運びも便利ですよね。

CSS-in-JSはファイル数を減らせるので管理が楽で、スタイルを適用したいコンポーネントも同一ファイル内にあるので、余計なファイル間の移動がなく、スタイルとコンポーネントの動的な関連付けもしやすいので便利です。

## テーマ編
CSS-in-JSがなんか良い感じっぽいのはわかったけれど、全コンポーネントに適用したい共通スタイルはどうすれば良いのか。
それを実現してくれるのが『テーマ』です。

テーマはMaterial-UIのStylesパッケージに同梱されており、下記のようにして使用します。

```JavaScript
import React from 'react';

import { createMuiTheme } from '@material-ui/core/styles';

const theme = createMuiTheme({
  palette: {
    primary: {
      main: '#00357f',
    },
    secondary: {
      main: '#11cb5f',
    },
    background: {
      paper: '#000',
    }
  },
  breakpoints: {
    values: {
      xs: 0,
      sm: 600,
      md: 960,
      lg: 1280,
      xl: 1920,
    },
  },
  typography: {
    h5: {
      fontSize: '5rem'
    }
  }
});
export default theme;
```

↓この部分でテーマの機能をパッケージからインポートします。

```JavaScript
import { createMuiTheme } from '@material-ui/core/styles';
```

好きなように設定を変更します。
上記の例を一部抜粋↓して解説すると

```JavaScript
  palette: {
    primary: {
      main: '#00357f',
    },
    secondary: {
      main: '#11cb5f',
    },
    background: {
      paper: '#444',
    }
  },
```

↑の部分でプライマリーカラー、セカンダリーカラー、Paperコンポーネントの背景色を変更しています。

あとは、コンポーネント側で↓の指定をしてあげるだけです。

```JavaScript
import React from 'react';
import { ThemeProvider } from '@material-ui/styles';

// ↓テーマの設定を記述したファイルをインポート
import defaultTheme from '~/styles/themes/defaultTheme';

const Top = ({ children }) => (
  <ThemeProvider theme={defaultTheme}>
    {children}
  </ThemeProvider>
)
```

もうお気づきの方もいるかもしれませんが、このテーマを↓のように動的に変更することで、ダークモードの実装も簡単に行うことができます。

```JavaScript
  <ThemeProvider theme={darkMode && darkTheme || defaultTheme}>
    {children}
  </ThemeProvider>
```
※darkThemeという別のテーマを作成する必要があります

上記のように[デフォルトで設定されたテーマ](https://material-ui.com/customization/default-theme/#default-theme)を自分好みにカスタマイズすることができます。

## セレクタ編
makeStylesでのCSSセレクタ記法をみていきましょう。
通常のCSSセレクタとほとんど同じなのですが、少しクセがあるので注意が必要です。
本記事では以下の主要なセレクタのみ紹介します。

1. [DOM要素(divやspan等)指定](#1-dom要素divやspan等指定-セレクタ)
2. [className指定](#2-classname指定-セレクタ)
3. [before / after](#3-before--after-セレクタ)
4. [keyframes](#4-keyframes-セレクタ)
5. [メディアクエリ](#5-メディアクエリ-セレクタ)

### 1. DOM要素(divやspan等)指定 [セレクタ]

```JavaScript
import { makeStyles } from '@material-ui/core/styles';

const useStyles = makeStyles(theme => ({
  top: {
    '& div': {
      height: '100vh',
    },
  },
}));

const Top = () => {
  const classes = useStyles();
  return (
    <div className={classes.top} />
      <div />
    </div>
  )
}
```

↑div要素を画面高さいっぱいにしたい時の例

### 2. className指定 [セレクタ]
```JavaScript
import { makeStyles } from '@material-ui/core/styles';

const useStyles = makeStyles(theme => ({
  top: {
    '& .empty-span': {
      height: '100vh',
    },
  },
}));

const Top = () => {
  const classes = useStyles();
  return (
    <div className={classes.top}>
      <span className="empty-span" />
    </div>
  )
}
```

↑empty-spanという名前のクラスを画面高さいっぱいにしたい時の例

### 3. before / after [セレクタ]
```JavaScript
import { makeStyles } from '@material-ui/core/styles';

const useStyles = makeStyles(theme => ({
  top: {
    '& span': {
      '&::before': {
        content: '""'
      },
      '&::after': {
        content: '""'
      }
    }
  },
}));

const Top = () => {
  const classes = useStyles();
  return (
    <div className={classes.top}>
      <span />
    </div>
  )
}
```

↑span要素にbeforeとafterを追加したい時の例

### 4. keyframes [セレクタ]

```JavaScript
import { makeStyles } from '@material-ui/core/styles';

const useStyles = makeStyles(theme => ({
  top: {
    animation: '$blink 1s linear infinite',
    '@keyframes blink': {
      '0%': {
        opacity: 1,
      },
      '50%': {
        opacity: 0,
      },
      '100%': {
        opacity: 1,
      }
    }
  },
}));

const Top = () => {
  const classes = useStyles();
  return (
    <div className={classes.top} />
  )
}
```

↑div要素を点滅させたい時の例

### 5. メディアクエリ [セレクタ]

```JavaScript
import { makeStyles } from '@material-ui/core/styles';

const useStyles = makeStyles(theme => ({
  top: {
    [theme.breakpoints.up('md')]: {
      background: 'red',
    },
  },
}));

const Top = () => {
  const classes = useStyles();
  return (
    <div className={classes.top} />
  )
}
```

↑960px以上の画面幅の場合、背景色を赤くしたい時の例

※『border-radius』のように"-"で繋がれたCSSスタイル属性は『borderRadius』といった風にキャメるのを忘れずに
（「キャメる」とはキャメルケースに変換するの意）

## 実践編

さきほど、keyframesのセレクタについて説明をしましたが
実は『[react-simple-animate](https://react-simple-animate.now.sh/)』という便利なパッケージと組み合わせることで、もっと汎用的なアニメーションを作成することもできます。

### react-simple-animate（アニメーション）
「アニメーションの設定を動的に行いたい」という場面に直面した時
『react-simple-animate』を使うと簡単に実現することができる

```JavaScript
import React from 'react';
import { useAnimateKeyframes } from 'react-simple-animate';

const ShakeAnimation = ({ children, iterationCount = 'infinite', duration = 5 }) => {
  const { style, play } = useAnimateKeyframes({
    iterationCount: iterationCount,
    duration: duration,
    keyframes: [
      { 0: 'transform: translateY(0)' },
      { 95: 'transform: translateY(0)' },
      { 96: 'transform: translateY(5px)' },
      { 97: 'transform: translateY(-5px)' },
      { 98: 'transform: translateY(5px)' },
      { 99: 'transform: translateY(-5px)' },
      { 100: 'transform: translateY(0)' }
    ]
  });

  <div style={style}>
    {children}
  </div>
}
export default ShakeAnimation
```
↑アニメーションの回数とアニメーション時間を動的に変更できる汎用的なコンポーネントをつくりたい時の例

```JavaScript
import React from 'react';
// ↓ファイル名とファイルのパスは適当に指定してください
import ShakeAnimation from '~/animations/ShakeAnimation';

const UseAnimation = () => (
  <div>
    <ShakeAnimation>
      <span>{'ここがアニメーションされるよ'}</span>
    </ShakeAnimation>
  </div>
)
```

↑のように使いたいコンポーネント側でインポートしてあげれば汎用的なアニメーションコンポーネントを使用できるようになります。

## まとめ
いががでしたでしょうか。
Material-UIを使えばデザインが苦手な方でも良い感じにアプリケーション開発ができるようになります。
また、Material-UIの「Styles」というパッケージを使用することで、デフォルトのデザインを自分好みに簡単にカスタマイズすることもできます。

今回はビギナー向けの使い方をメインにご紹介しましたが、Material-UIコンポーネント同士のよくある組み合わせ方や実際のWebアプリケーションでの実用例なんかも機会があれば紹介できたらなと思っています。

**それでは、よいMaterial-UIライフを！**