Tailwind + PostCSS, styled-jsx を用いた Next.js Application 上でのスタイル適用

[こちら](https://qiita.com/toshipon/items/19e9efcd436343403b5d) の記載した、小中規模 Next.js Application 開発における Tailwind CSS を用いたスタイルの適用の方針をもう少し具体的に記載したいと思います。

# 全体のテーマ、スタイルの適用

Tailwind の定義する CSS Class のスタイル(色、フォントサイズ、margin, padding の大きさ等)は `tailwind.config.js` というファイルを拡張することによって変更が可能です。

変更しやすいように、`tailwind.config.js` の全てのデフォルト値が以下に記載されているため、このファイルを自リポジトリにコピーして、コピーしたファイルをカスタマイズしていきます。

[https://github.com/tailwindcss/tailwindcss/blob/master/stubs/defaultConfig.stub.js](https://github.com/tailwindcss/tailwindcss/blob/master/stubs/defaultConfig.stub.js)

( ただし開発していく中で明らかに拡張しない設定などがわかってきたら不要な行を削っていっても良いかと思います。ファイル自体が結構大きいので視認性が悪いため）

プロジェクトに合った、トンマナの情報や、figma等のデザインデータの規則性のある数値を読み取って `tailwind.config.js` に落とし込んで tailwind の CSS Class を利用するのみでスタイルができようできるような状態をなるべく目指します。

# 共通の独自スタイルの定義

Component に依存しない共通のスタイルは エントリーポイントであるCSSファイルを用意して、そのCSSファイルに独自のスタイルを定義していきます。

 例えば、font-size を rem ベースで記述していきたいとき、10px を 1rem と基準となるサイズを変更して利用します。そういった共通のスタイルはすべて CSS ファイルに記載していきます。

また、Component に依存しないような CSS Class もこのファイルに定義します。

なお、Tailwind のCSS Class を有効にするために @\tailwind ディレクティブを利用して Tailwind の CSS ルールを注入します。

```css:src/style.css
@tailwind base;
@tailwind components;

html {
  @apply h-full;
  /* remの基準を10pxとおいて、remでのfont-size指定をしやすくする */
  font-size: 62.5%;
}
body {
  /* ベースを14pxとする */
  @apply text-base p-3 h-full;
}

.main {
  @apply bg-white my-3 mx-auto px-4 pt-1 pb-6 rounded-lg;
}

@tailwind utilities;
```

## @\apply ディレクティブを用いた Tailwind の拡張

Tailwind の CSS Class を組み合わせて独自のCSS Class を作成して共通化を計りたい場合は、 @\apply を用いて、インラインで Tailwind の CSS Class を呼び出して独自の CSS Class に対してスタイルを継承することができます。

この方法で極力自力でスタイルを記述せずにスタイルを適用することができ、全体のスタイルを一括して調整が後からしやすくなります。

https://tailwindcss.com/docs/functions-and-directives/#apply
https://tailwindcss.com/course/composing-utilities-with-apply/#app

# 各 Component 依存のスタイルの定義

React.js の小さく分解された共通化可能な Component のスタイル調整は、対象のComponent の中でスタイルを定義して、依存するスタイルを明確にして変更管理をしやすくします。

## styled-jsx を用いたスタイルの定義

styled-jsx を用いて Component 依存のスタイルを定義します。

Component の className に直接 tailwind の CSS Class を適用してしまうと冗長になって視認性が悪くなるため、 styled-jsx で CSS Class を定義してあげてスタイルを適用していきます。

```tsx
export default function Input(props: Props) {
  return (
    <>
      <input
        className="input-text"
      />

      <style jsx>{`
        .input-text {
          @apply appearance-none border-b rounded w-full p-3 text-gray-700 leading-tight;
        }
      `}</style>
    </>
  );
}
```

## 変数を用いた動的なスタイルの適用

styled-jsx ではスタイルの中で変数を展開できるので、JavaScriptの値を使って動的にスタイルを適用することができます。

```tsx
export default function Button(props: Props) {
  return (
    <>
      <button
        className={`btn ${props.variant == 'primary' ? 'primary' : 'secondary'}`}
      >
        {props.children}
      </button>

      <style jsx>{`
        .btn {
          @apply font-bold p-4 w-64 rounded;
          backgroud-color: ${props.color}
        }
      `}</style>
    </>
  );
}
```

ただし、tailwind の @\apply 宣言の中のインライン定義内で変数を展開することはできないので、tailwind の CSS Class を用いて動的にスタイルを切り替えたい場合は以下のように CSS Class を予め宣言しておいて、利用する CSS Class を切り替える等の処理が必要です。

```tsx
export default function Button(props: Props) {
  return (
    <>
      <button
        className={`btn ${props.variant == 'primary' ? 'primary' : 'secondary'}`}
      >
        {props.children}
      </button>

      <style jsx>{`
        .btn {
          @apply font-bold p-4 w-64 rounded;
        }

        .primary {
          @apply bg-blue-500 text-white;
        }

        .secondary {
          @apply bg-white text-gray-600;
        }
      `}</style>
    </>
  );
}
```

# モバイル用のスタイルの調整

Tailwind はレスポンシブデザインに対応しているため、以下の  @\screen ディレクティブを用いてディスプレイサイズ毎のスタイルの宣言を行います。

```css
.card {
  border-radius: 0;
}
@screen sm {
  .card {
    border-radius: theme('borderRadius.lg');
  }
}
```

# 各種設定ファイルの変更

以下は、Next.js Application 上で Tailwind + PostCSS を styled-jsx を用いて 利用するための設定変更になります。

```json:.babelrc
{
  "presets": [
    [
      "next/babel",
      {
        "styled-jsx": {
          "plugins": ["styled-jsx-plugin-postcss"]
        }
      }
    ]
  ]
}
```

```tsx:postcss.config.js
module.exports = {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
    "postcss-flexbugs-fixes": {},
    "postcss-preset-env": {
      autoprefixer: {
        flexbox: "no-2009",
      },
      stage: 3,
      features: {
        "custom-properties": false,
      },
    },
  },
};
```

依存ライブラリの追加

```bash
yarn add tailwindcss -D
yarn add lost styled-jsx styled-jsx-plugin-postcss -D
yarn add postcss-flexbugs-fixes postcss-nested postcss-preset-env postcss-import -D
```