ReactでTailwindを使ってみた

# はじめに

最近流行りの`Tailwind CSS`を使ってみました。

筆者は普段、`Bootstrap`を主に使用して仕事してます。

`Bootstrap`と比べて何が良いんだろうと比べつつ私が思うメリット、デメリットを考えてみたいと思います。

[今更ながら graphql-code-generator の便利さを痛感する](https://qiita.com/pure-adachi/items/c0858fe4e143a93d1927)で作成した、TODOアプリに `Tailwind CSS`を導入して、感触を確かめてみようと思います。

今回作成する内容は`graphql-code-generator`のサンプルが主ですが、[GitHub](https://github.com/pure-adachi/graphql-code-generator-sample-frontend)に置いてあります。

このTODOアプリは、`create-react-app`で作成しており、特にスタイルは変更していません。
`Tailwind CSS`を入れる前は、こんな感じです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304414/2aaecbbb-e2df-982c-eedc-ff61a0679bca.png)


# インストール

[公式](https://tailwindcss.com/docs/guides/create-react-app#install-tailwind-via-npm)通りにやりますが、私は`yarn`で入れます

```sh
$ yarn add -D tailwindcss@npm:@tailwindcss/postcss7-compat postcss@^7 autoprefixer@^9
```

[CRACOを使わないといけない](https://tailwindcss.com/docs/guides/create-react-app#install-and-configure-craco)らしいのでインストールする

```sh
$ yarn add @craco/craco
```

# cracoの設定

`react-scripts`を使用している`eject`以外のスクリプトを`craco`に変更します。

```diff:package.json
 "scripts": {
-  "start": "react-scripts start",
-  "build": "react-scripts build",
-  "test": "react-scripts test",
+  "start": "craco start",
+  "build": "craco build",
+  "test": "craco test",
   "eject": "react-scripts eject",
 }
```

`craco`で動かすので、設定ファイルを作成します。

```js:craco.config.js
module.exports = {
  style: {
    postcss: {
      plugins: [
        require('tailwindcss'),
        require('autoprefixer'),
      ],
    },
  },
}
```

この時点で、`craco`の設定は完了しているので、動くようにはなりました。

# tailwindの設定

```sh
$ yarn tailwindcss init
```

`tailwind.config.js`ファイルが生成されました。

本番環境用に、このファイルの`purge`というところの設定を変更するそうです。
`tailwind`はかなり多くの`class`を用意していますが、本番環境でも全ての`class`定義を読み込んでしまうと重たくなってしまいます。
この設定は、未使用の`class`は読み込まないようにする設定となります。

今回は、本番で動作させないのでスキップします。
本番環境用の設定を行いたい場合は、[こちら](https://tailwindcss.com/docs/guides/create-react-app#configure-tailwind-to-remove-unused-styles-in-production)を参照してください。

`Tailwind CSS`を使う下準備は整ったので、今のスタイル（ロゴも）を全て削除してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304414/fa0a9d62-75e6-3b9d-e307-c7d7e2f1b934.png)

このまっさらな状態に、`Tailwind CSS`のスタイルを少しずつ当てていきたいと思います。

# Tailwind CSSのclassを利用できるようにする

```css:src/index.css
@tailwind base;
@tailwind components;
@tailwind utilities;
```

この時点では、こんな感じです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304414/13f1fd05-902e-c3b1-38da-5f37a3d11a44.png)

# 画面の真ん中辺りに表示してみる

左上に表示されてしまっているので、真ん中辺りにカードを用意し、その中にリストが並んでいる感じにしてみます。

## とりあえず真ん中に表示

`flex items-center justify-center`の`class`を追加して真ん中に表示します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304414/4c5f9227-c66e-a944-c757-defe0bcd6724.png)

水平方向には中央揃えされましたが、垂直方向には中央揃え出来てません。
※位置関係がわかりにくいので、`html`タグに`bg-gray-500`の`class`を追加して色付けしてます。

![スクリーンショット 2021-08-09 16.00.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304414/f3518c71-f959-2714-7b22-26e0b5ae26c0.png)

`flex`をつけた要素がそもそも小さいようです。
高さを追加してやります。

`tailwindcss height`と調べて[ここ](https://tailwindcss.com/docs/height)に辿り着きました。

かなり多くの`class`が用意されていますね。

`Bootstrap`にも`100vh`の高さを指定する用の`vh-100`がありますが、種類に関しては、`tailwindcss`の方が多いと実感させられますね。

今回は、高さを目一杯広げたいので、`flex`を追加した要素に`h-screen`を追加します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304414/1457a983-f6d4-3d02-acd6-28a69b61a4b0.png)

垂直方向にも中央に表示されました。

# カード形式で表示させてみる

`Bootstrap`脳なので、`card`的な`class`を使いたいところですね。

## 中央要素の背景色を白っぽくしてみる

まずは、中央要素の背景を`bg-white`を使って白くしてみました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304414/0d67a1cc-e5ea-c1d3-fa81-f9dc2d00ee06.png)

[用意されている背景色用のclass](https://tailwindcss.com/docs/background-color)を見てみましたが、やっぱり豊富ですね。

せっかくなので`bg-white`ではなく`bg-gray-50`にしておきます。（あんまり変わりませんがなんとなく）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304414/6cd618e4-d878-dd87-aaf1-ff9fcf3ef5d3.png)

## 角に丸みをつけてパディングをつけてみる

[border-radius](https://tailwindcss.com/docs/border-radius)も多いっすね〜
`rounded-lg`にしてみますか

[padding](https://tailwindcss.com/docs/padding)は、`p-8`辺りにしてみます。

`bg-gray-50`を追加した要素に`rounded-lg`と`p-8`を追加します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304414/2ec41e7b-d178-b041-9b63-81693789d957.png)

なんか一気に雰囲気が出てきました

## 影もつけてみる

背景色が結構濃い色になってるので、[box-shadow](https://tailwindcss.com/docs/box-shadow)から、きつめの`shadow-2xl`を選びました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304414/4d045b4a-f5c0-2e4f-0f9f-cb10e9de80dd.png)

うん、いい感じ

# カードのタイトルをいい感じにする

カードの中のスタイルをつけていきます

`Bootstrap`脳だと`card-title`とかつけるとこですね

タイトルが`create-react-app`で作った時のままになってるので、文言を変えます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304414/b1ed8b46-1468-c44b-87dc-71b515924cff.png)

## 文字サイズと文字色を変更

[font-size](https://tailwindcss.com/docs/font-size)から探して、`text-3xl`くらいにしてみます。

せっかくなので文字色も[text-color](https://tailwindcss.com/docs/text-color)から探して、`text-red-800`にしてみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304414/24dd98f0-87c2-642d-8d24-fae23c79377d.png)

# 入力欄をいい感じにする

Todoの名称を入力する入力フィールドにスタイルをつけていきます

上下の要素と距離感が近いので余白をあけます

[margin](https://tailwindcss.com/docs/margin)から探して`my-4`をつけてみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304414/48a334f4-3169-979e-fc30-209c4607bfaf.png)

あとは、枠線、影、角の丸み、paddingあたりをつけてみます。

- [border](https://tailwindcss.com/docs/border-width)から`border`
- [box-shadow](https://tailwindcss.com/docs/box-shadow)から`shadow`
- [border-radius](https://tailwindcss.com/docs/border-radius)から`rounded`
- [padding](https://tailwindcss.com/docs/padding)から縦は`py-2`、横は`px-3`

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304414/a0cfb1e0-6f6f-5a5d-198f-0fc40ecb2270.png)

いい感じになってきました

# リストをいい感じにする

リストで表示している部分にスタイルをつけてきます

Todo名とボタンが近いのでこれをなんとかします

Todo名を８０％くらい、ボタンを20%くらいの4/5 - 1/5って感じにしたいですね〜

[width](https://tailwindcss.com/docs/width)を探すと`w-1/5`とか`w-4/5`ってやつがありました。

`li`タグに`flex`をつけて、Todo名の要素に`w-4/5`、ボタン要素に`w-1/5`をつけてみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304414/2d9939b1-b271-bc26-438d-85ac796af3a8.png)

いい感じに離れてくれました。

## リスト同士にも距離感をつけてみる

リスト同士も少し距離感が近いので、`li`に`py-2`をつけてみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304414/7d82b070-598a-2444-f728-dfe22f545599.png)

## マウスオーバーでリストの背景色を変えてみる

リストをホバーした際、`li`要素を`bg-gray-200`な背景色に変えてみます。

`li`要素に`hover:bg-gray-200`を追加するだけでした。
これはめっちゃ便利

![hover.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304414/7bcefc99-5e21-2764-7d74-334065e9c3a5.gif)

Todo名の左に余裕がないのと、ホバーした際の背景色領域の角に丸みをつけてよりいい感じにします。

Todo名の要素に`px-1`を追加、`li`タグに`rounded`を追加しました。

![hover2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304414/4129a499-1335-387c-8440-2de02bb338d8.gif)

## 削除ボタンをいい感じにする

削除ボタンにスタイルをつけていきます

付けたいスタイルは以下です。

- 枠線
    - [border-width](https://tailwindcss.com/docs/border-width)から`border-2`
- 枠線の色
    - [border-color](https://tailwindcss.com/docs/border-color)から`border-red-400`
- パディング
    - [padding](https://tailwindcss.com/docs/padding)から`p-2`
- 改行禁止
    - [whitespace](https://tailwindcss.com/docs/whitespace)から`whitespace-nowrap`
- 角の丸み
    - [border-radius](https://tailwindcss.com/docs/border-radius)から`rounded`
- 文字色
    - [text-color](https://tailwindcss.com/docs/text-color)から`text-red-400`
- ホバー時（`hover:`）
    - 文字色
        - [text-color](https://tailwindcss.com/docs/text-color)から`text-white`
    - 背景色
        - [background-color](https://tailwindcss.com/docs/background-color)から`bg-red-400`

![btn hover.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304414/f5934a96-a505-391a-9075-9a015a74438b.gif)

ボタンから文言がはみ出てしまってますね

## カードの幅を大きくする

`h-screen`を追加した要素に、`p-20`を追加して、`bg-gray-50`を追加したカード要素に`w-full`を追加します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304414/4c416da8-6a3d-0613-757c-4d5f044f8a7c.png)

Todo名とボタンの表示高さがズレているので、`items-center`を`li`要素に追加します。

あと、入力欄も小さいので`w-full`をつけて大きくします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304414/c6bed6a1-0b9e-e7ac-8554-662a55eb83f7.png)

ボタンのサイズが大きくなっているのが気になりますね〜
あと、Todo名が長すぎる場合、改行されてしまうので、なんとかしたいです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304414/fd068a3f-1dc7-3a7d-5d96-1b11c3890a52.png)

## ボタンのサイズを必要最低限にして、Todo名がはみ出たら`...`で表示する

Todo名の`w-4/5`とボタンの`w-1/5`を削除して、Todo名要素に[flex-auto](https://tailwindcss.com/docs/flex)をつけます

Todo名がはみ出たら`...`にする為に、[text-overflow](https://tailwindcss.com/docs/text-overflow)の`truncate`をTodo名要素につけます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304414/2c492c4f-a504-733a-5700-7d7e74092c96.png)

ここまでくると、実は気になっていた、Todoを登録するボタンがバランス的に欲しくなってきました。

# Todoの登録ボタンを追加してみる

Tailwindの話から一時的に逸れますが登録ボタンを追加しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304414/d9acb862-1650-b318-1c0c-608796f74b7d.png)

削除ボタンの`blue`バージョンを登録ボタンのスタイルにしました。

# レスポンシブにもしてみる

今は、画面の表示領域に余裕がある前提でやっているので、これを小さくてもいい感じに見えるようにしてみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304414/0a576e11-b804-cf4f-975d-6edd73dbf10c.png)

それほど表示している項目が多いわけではないので、違和感があると言われたらあんまりないですが、`Tailwind CSS`のレスポンシブを体験してみます。

## 画面幅が小さければ、カードのサイズを少し広げてみる

[responsive-design](https://tailwindcss.com/docs/responsive-design)に用意されているように、`sm`や`lg`のように接頭辞をつけると画面幅の状況によって、反映させたいスタイルを変更することができるとのことです。

`hover`の時とおんなじ感じですね。

`h-screen`を使っている要素では、`p-20`としていましたが、これを`lg:p-36 md:p-28 sm:p-20 p-4`に変更します。

`p-4`と接頭辞をつけていないものがある理由は[こちら](https://tailwindcss.com/docs/responsive-design#targeting-mobile-screens)にも記載があるように、接頭辞がないものをモバイル（画面が小さい時）に反映させたい`class`という風にするそうです。

`sm`をつけている`p-20`は、画面幅が`640px`以上の時に反映されます。
`md`をつけている`p-28`は、画面幅が`768px`以上の時に反映されます。
`lg`をつけている`p-36`は、画面幅が`1024px`以上の時に反映されます。
接頭辞をつけていない`p-4`は、画面幅が`640px`より小さい時に反映されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304414/bfbb8a9a-b5e8-ae85-c816-96c6f4a9d3e7.png)

↑ chromeで表示できる一番小さいサイズにした時、カードの幅が広がりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304414/79eb2a39-b75d-6f33-d700-5e3173b13224.png)

↑ 画面幅が`1024px`なので、`p-36`が反映されました。

# 画面幅が小さいときは、Todoの追加が行いやすいように入力欄の下に大きく表示できるようにしてみる

画面幅が`640px`より小さい場合を画面幅が小さい時とします。

- 入力欄とボタンを横並びにする為に、`flex`を使用しているこれを、`sm:flex`にする。
- 登録ボタンの横幅を`w-full`にする
    - 画面幅が`640px`以上の場合、`w-auto`にする為に、`sm:w-auto`にする
- 登録ボタンの左のマージンに`sm:`をつける
- 入力欄の下に画面幅が`640px`より小さい場合、登録ボタンとの間隔を空ける為に`mb-3`をつける
    - 画面幅が`640px`以上の場合、`mb-0`にする為に、`sm:mb-0`にする

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304414/36f3ce9d-dcff-2cba-ef85-5d8e9fdd84f5.png)

↑ 画面幅が小さい場合は、登録ボタンが入力欄の下に大きく表示されるようになりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/304414/c872e143-0a40-e349-8166-e463e7060318.png)

画面幅が大きい場合は、これまで通り表示されます。

いい感じになったのではないでしょうか！

# 終わりに

実際に使ってみて感じた個人的なメリット、デメリットをあげてみます。

## メリット

- 用意されている`class`が豊富で、自分でスタイルを定義する必要がなさそう
    - 自分でスタイルを定義すると、クラス名とか考えないといけないので大変な部分が解消
- `sm`とか`md`とか、`hover`とかの接頭辞をつけるだけで、色々できるので、超簡単
- 公式サイトの`class`の説明が見やすいので調査コストが少ない？

## デメリット

- 凝ったデザインにすると`class`がかなり長くなる
    - 今回一番長かったのは登録ボタンのこれ
        - `sm:ml-3 border-2 p-2 whitespace-nowrap rounded text-blue-400 border-blue-400 hover:text-white hover:bg-blue-400 sm:w-auto w-full`
    - HTMLが汚くなりそうだけど、ReactとかVue.jsは、変数にクラス名を詰め込んでおいて、それをコンポーネントで利用するとHTMLの部分は綺麗に書くこともできそう？
        - 結局変数名を考えてしまっているので、スタイルを定義する時のクラス名を考えるのと同コストかも？
- 同様の凝ったスタイルを別の箇所で利用する時、冗長になりそう
    - ReactやVue.jsでは共通コンポーネントにしてしまうことで解消できそう？
- cssの知識がある前提
    - 当たり前と言われれば当たり前
    - `Bootstrap`を利用したことがあって、`Bootstrap`が用意している`class`名だけを覚えている人は大変かも

普段`Bootstrap`を使って仕事している筆者は、〇〇なスタイルが含まれたクラスはないかな〜って感じで調べることもあるので、個人的には、スタイル直なクラスが用意されている方が嬉しみがあったので、使い勝手が良さそうな感触でした。

# 参考文献

https://tailwindcss.com/docs/guides/create-react-app
https://reffect.co.jp/react/react-tailwind