JAMStack作成の軌跡Part3

## はじめに

- [前回](https://qiita.com/krkettle57/items/db23c433ec4ea7fb26e4)でGatsbyのTypeScript化、開発環境の拡張を行った
- 今回は[TailwindCSS](https://tailwindcss.com/)を導入していく
- 完成形は[こちら](https://github.com/krkettle57/gatsby-sample/tree/blog-part3)

## [TailwindCSS](https://tailwindcss.com/)とは

- 自分の言葉で解釈してみると「**よく使うスタイルに分かりやすい名前をつけて標準化しつつ、拡張性のあるCSS**」になるのかな
- 食パンの6枚切り、8枚切りとかのイメージ
  - (蛇足) 食パンの1斤って大きさじゃなくて重さの単位なんだね。しかも下限値。
- メリット・デメリットに関しては以下の記事を参考にした
  - [Tailwind CSSのメリットとデメリット](https://coliss.com/articles/build-websites/operation/css/a-look-at-tailwind-css.html)

### 素のCSSとTailwindCSSの比較

- 画面の中央に「Hello World」表示するだけのHTML + CSSを書いてみる

  ```html
  <div class="box">
    <p class="text">Hello World</p>
  </div>

  <style>
    .box {
      background-color: lightgray;
      min-height: 100vh;
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
    }
    .text {
      font-size: 1.5rem;
    }
  </style>

  ```

- これをtailwindcssに置き換えてみると以下の通り

  ```html
  <div class="bg-gray-200 min-h-screen flex flex-col justify-center items-center">
    <p class="text-2xl">Hello World</p>
  </div>
  ```

  - `min-height: 100vh;`というCSSが事前定義されたクラス名`min-h-screen`に対応している
    - 対応表は[CheatSheet](https://nerdcave.com/tailwind-cheat-sheet)が参考になる
    - `font-size: 1.5rem`と`text-2xl`などは完全に対応しているわけではない
  - ※ 実際にHTMLで表示させるときは[CDN](https://tailwindcss.com/docs/installation#using-tailwind-via-cdn)を利用した

### TailwindCSSのメリット

1. クラス名を考える必要がない
   - 事前定義したクラスを書き連ねるだけなので、上記の`box`, `text`と言ったクラス名を考える必要がない
   - 考える時間の削減に加え、クラスの命名規則の標準化などから解放される
2. 素のCSSにおけるinline-styleでのデメリットを解消できる
   - 事前定義されたクラスを利用するという制約をかけることで**「考える」から「選ぶ」に移行**出来る
   - マルチデバイス対応のためにmediaクエリを書く場合、inline-styleでは出来ないがtailwindcssでは可能
   - Hover, focusなどの状態管理はinline-styleでは出来ないがtailwindcssでは可能
   - 参考: [Why not just use inline styles?](https://tailwindcss.com/docs/utility-first#why-not-just-use-inline-styles)

### TailwindCSSを使おうと思った理由

1. CSSをガッツリ書いた経験がなかったから
   - 業務では基本的にデータ分析やサーバサイドメインで、フロントエンドの経験がないこと
   - 過去にReactをちょろっと触った時はCSS何もわからんと思いながら、[Material-UI](https://mui.com/)におんぶに抱っこだったので今回挑戦してみる
   - ただ、素のCSSは自由度が高かったため、tailwindcssは丁度良いと思った

2. TailwindCSSが公式でGatsbyとの連携を紹介している
   - [公式ドキュメント](https://tailwindcss.com/docs/guides/gatsby)に統合ガイドが載ってる
   - Gatsbyでも問題なく使えそうなので安心

3. 流行ってたから
   - (白状すると流行ってるから触ってみたかった...)

## Gatsbyへの導入

[公式ドキュメント](https://tailwindcss.com/docs/guides/gatsby)に従って進めていく

### TailwindCSSのインストール

```sh
yarn add -D gatsby-plugin-postcss tailwindcss@latest postcss@latest autoprefixer@latest
npx tailwindcss init -p
```

- tailwind.config.jsとpostcss.config.jsの2つのファイルが作成される
  - tailwind.config.js
    - テーマやプラグインの設定を記述する
    - `purge`については後述
    - 参考: [Configuration](https://tailwindcss.com/docs/configuration)
  - postcss.config.js
    - SassとかPostCSSとかと連携したい場合の設定を記述する
    - ただ、他のプリプロセッサとTailwindを一緒に使う必要はないよって公式ドキュメントで言ってる
    - 参考: [Using with Preprocessors](https://tailwindcss.com/docs/using-with-preprocessors)

### purgeの設定

- tailwind.config.jsの`purge`を修正する

```js
purge: ['./src/**/*.{js,jsx,ts,tsx}'],
```

- purgeとは「不要なものを取り除く」的な意味がある
- ん？src/下のファイル群不要じゃないんやが...と思ったが違う、そうじゃない。
- tailwindcssは実質無数のクラスが用意されたCSSなので、**そのままだとビルドサイズが大きい**
- そこで、**purgeで指定したファイル群から参照されなかったのクラス**を不要なものとして取り除くよって意味らしい
- 参考: [Tailwind CSS の Purge でビルドサイズを縮小する](https://zenn.dev/ryo_kawamata/articles/purage-tailwind)

### pluginの設定

- gatsby-config.jsに`gatsby-plugin-postcss`をプラグインとして登録する

  ```js
  plugins: [
    // 省略
    'gatsby-plugin-postcss'
  ]
  ```

### CSSの読み込み

- src/styles/global.cssにtailwindの設定を記述する

  ```css
  @import "tailwindcss/base";
  @import "tailwindcss/components";
  @import "tailwindcss/utilities";
  ```

- gatsby-browser.jsでcssをimportする

  - ブラウザで表示させる際の設定を記述するファイル
  - グローバルなCSSを読み込む場合もここで記述する

  ```js
  import './src/styles/global.css';
  ```

## TailwindCSS対応

- ページはindex.tsxのみを対象として、残りのページは削除する
- TailwindCSSで元のページを完全再現するのではなく、大きく外れないように移行してみる

### CSSからTailwindCSSへの修正時に湧いた疑問

- ※tailwindcssの悩みというよりはCSSに慣れてない私の悩み
- 細かいことは気にしないのであれば、移行自体は簡単に出来た
  - 参考: [CheatSheet](https://nerdcave.com/tailwind-cheat-sheet)
- しかしindex.tsxで`<p>`タグが2つ出てきた時に「あれ、これ2つの`<p>`タグに同じ`className`指定するの？いやいやいや...」という疑問が湧いた

### CSSをどこに書くか

- フロントに慣れていない私は全然知らなかったが色々流派があるらしい

  - 参考: [Reactのコンポーネントのスタイリングをどうやるか](https://qiita.com/lightnet328/items/218eb1c4a347302cc340)

- ※CSS-in-JSやCSS Moduleなど調べる程深みにハマりそうだった
  良い方法かは分からないが、一旦「えいや！」で決めて
  良くなさそうだったら後から修正するスタイルにした(以下、参考にした記事)

  - [色々書き比べた結果Tailwind CSSにしたという話](https://qiita.com/Takazudo/items/78ee15564bfefdea844c)
  - [Next.js が CSS Modules を推奨する真相に迫りたい](https://zenn.dev/takepepe/scraps/6668e9fe402666)

  

- 今回は以下に配置することにした

| 配置                 | 役割                                           |
| -------------------- | ---------------------------------------------- |
| src/style/global.css | 全体で共通のCSS(`@tailwind`ディレクティブなど) |
| src/components/*.css | コンポーネント毎のCSS                          |

  - body全体に適用するスタイリングは`@layer base`を用いてベーススタイルをカスタマイズするようにした

    ```css
    @tailwind base;
    @tailwind components;
    @tailwind utilities;
    
    @layer base {
      body {
        @apply font-serif text-lg;
      }
    }
    ```

    - 以下を参考にした
      - [Preflight](https://tailwindcss.com/docs/preflight)
      - [Adding Base Styles](https://tailwindcss.com/docs/adding-base-styles)
      - [Functions & Directives](https://tailwindcss.com/docs/functions-and-directives)
  
  - src/components/*.cssはlayout.jsのように子要素を持つコンポーネント にはタグごとのスタイリングを記述したが、global.cssに書いても良いかなと思っている
  
    ```css
    h1 {
      @apply mx-0 mt-0 mb-6 text-4xl font-sans font-bold;
    }
    
    p {
      @apply mx-0 mt-0 mb-6;
    }
    ```
  
    - ※applyを使うことに対する危惧が以下の記事に書かれていたが、今回は大規模な開発ではない、フロントエンドを触ってみることが目的のため、細かい点は一旦気にしないことにした。
      - [Tailwind CSSが私には合わなかった理由](https://coliss.com/articles/build-websites/operation/css/why-tailwind-css-is-not-for-me.html)
    - pタグの疑問に関してはこれで解消とした

### スタイリングの共通化

- 以下の方法が考えられる
  - クラスを`@apply`で新たに定義する
  - 新たにコンポーネント を定義する
- 共通化するには名前をつける必要があるのは仕方ないと思うが、CSSが適用されるスコープは小さくしたいので、原則コンポーネント を定義した方が良さそう
- 小さいスコープの中でしか利用されないなら、新たにクラスを定義しても良さそう

## TailwindCSSを導入した感想

- CSS初心者としては一からCSSを考えて書くより、ユーティリティクラスから選ぶ方法は扱いやすかった
- 一方で`className`でCSSを定義することでHTMLとCSSを1つのファイルで表現するか、別々にするかで意見が分かれるのは納得できる
  - 共通化する場合は管理コストが上がるのでCSSを分離してDRYに描きたい
  - 共通化する必要がないものはHTMLに書いた方が管理が楽
  - CSS-in-JSには踏み込んでいないものの、今回はGatsbyで静的サイトを作成するため、優先度は低くしてもよいかなと思っている
- Material-UIのようにコンポーネント のテンプレート集はtailwindcssでもあるようなので、いずれ使ってみたい
  - 参考: [Tailwind CSSで実装されたUIコンポーネント・ページテンプレート、商用プロジェクトで無料のものをまとめました](https://coliss.com/articles/build-websites/operation/css/tailwind-css-ui-components-libraries.html)