TailwindCSS入門 ~ Utility First + デザインシステムの構築 ~

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

>迅速かつ簡単にデザインシステムを構築するための**ユーティリティ**

を提供するフレームワークです。

これだけではよくわかりませんね。

そこでまずは、Tailwindの**Utility First**の概念を、例を交えて説明していきます。

## Utility First

Tailwindには`.button`のようなクラスはありません。

一方で、`.flex`クラスが存在します。

これは、CSSのflexプロパティに対応しています。

```css
.flex {
  display: flex;
}
```

どうして、そのような仕様にしているのでしょうか？

まずは、**記載量が減る**ということです。

これは、Tailwindを使わない場合と使った場合の比較です。

##### 使わない場合

```html
<style>
  .sample {
    display: flex;
    justify-content: center;
  }
</style>

<div class="sample"></div>
```

##### 使った場合

```html
<div class="flex justify-center"></div>
```

記載量が一気に減りました。

もう一つ、紹介させてください。

画面の幅によってスタイルを切り替える例です。

##### 使わない場合

```html
<style>
  .sample {
    display: flex;
    flex-direction: column;
  }

  @media (min-width: 640px) {
    .sample {
      display: flex;
      flex-direction: row;
    }
  }
</style>

<div class="sample">
  <div>a</div>
  <div>b</div>
</div>
```

##### 使った場合

```html
<div class="flex flex-col sm:flex-row">
  <div>a</div>
  <div>b</div>
</div>
```

メディアクエリを書かなくていい分、簡潔になりました。

このようにTailwindでは、

- CSS Propertyに対応するクラス（e.g. `.flex`）
- 特定のブレークポイントや、疑似クラスに対応するクラス（e.g. `.sm:font-lg` `.hover:flex-row`）

が用意されていて、単一のクラスで様々なスタイルを表現でき

記載量が大きく減る為、コードの可読性が上がります。

### デザインシステム

Tailwindが提供するクラスの特徴として、下記のようなものがあります。

文字の色を表します。

- `text-red-100`（薄い赤）
- `text-red-200`
- `text-red-300`
- `text-red-400`
- `text-red-500`
- `text-red-600`
- `text-red-700`
- `text-red-800`
- `text-red-900`（濃い赤）

よくあるカラーパレットですが、これと同じことがフォントサイズ等でも可能です。

- `text-xs`（小さい）
- `text-sm`
- `text-base`（デフォルトのサイズ）
- `text-lg`
- `text-xl`
- `text-2xl`（大きい）※6xlまであります。

そのほかにも、`width`や、`margin`・`border-radius`など、あらゆるスタイルに飛びとびでクラスがあり、

- **意思決定コストを下げる**

ことができます。

文字の大きさを「40pxにするか42px」にするか、悩むことは相当こだわりがない限り、無駄だったりします。

また、既にあるクラスからピックアップすることで、

- **チーム内でテーマを統一する**

ことができます。

そうしたスタイルガイド、ひいては**デザインシステムの構築を可能にする**のが、Tailwindです。

そして、Tailwindを使う更なるメリットは、

- **容易にカスタマイズ可能である**

ことです。

私たちは「**ユーティリティを自ら創りだす**」ことができます。

そういった意味で、Tailwindは

> **Utility First**なフレームワーク

なのでした。

では、Tailwindを用いた

- カスタマイズ
- デザインシステムの構築

をしていきます。

## インストール

まずは、npmでインストールをします。

```bash
npm install --save-dev tailwindcss
```

最小限だと、styles.cssを作り、

```css:styles.css
@tailwind base;

@tailwind components;

@tailwind utilities;
```

下記のコマンドを実行すると、output.cssがビルドされます。

```bash
npx tailwind build styles.css -o output.css
```

あとは、HTMLから読み込むだけで利用できます。

```html
<link rel="stylesheet" href="../output.css" />
```

### ソースバンドラーを利用する場合

Webpackなどを用いる場合は、PostCSSのプラグインが用意されています。

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

こうすることで、Tailwindのビルドをバンドラーの中ですることができます。

## カスタマイズする

早速、カスタマイズをしていきます。
下記のコマンドを打つと、設定用ファイルが作成されます。

```bash
npx tailwind init
```

ルートディレクトリに「tailwind.config.js」が作成されました。

```js:tailwind.config.js
module.exports = {
  theme: {
    extend: {}
  },
  variants: {},
  plugins: []
}
```

以下のプロパティがありますね。

- `theme`
    - `extend`
- `variants`
- `plugins`

それぞれについて、説明していきます。

### [Theme](https://tailwindcss.com/docs/theme)

Themeではあらゆる値を定義することができます。

- 画面のブレークポイントの定義
- カラーパレットの定義
- フォントサイズの値の定義 [etc…](https://tailwindcss.com/docs/theme#configuration-reference)

例えば、画面のブレークポイントを定義する際は、

```js:tailwind.config.js
module.exports = {
  theme: {
    screens: {
      small: '500px',
      medium: '800px',
      large: '1024px',
    },
  },
  ...
}
```

とします。こうすると、

`text-sm` - 小さめの文字のスタイル

というクラスに対して、

`small:text-sm` - viewportの幅が**500px以上**の要素に対するスタイル

というクラスがビルド時に生成され、使用できます。

```html
<!-- 大きい画面では文字が大きくなる -->
<button class="text-sm small:text-lg">
```

#### extend

前の例だと、既定値を上書きしてしまいます。

Tailwindでは既定で、

- `sm:` 640px以上の画面に適用される
- `md:` 768px以上の画面に適用される
- `lg:` 1024px以上の画面に適用される
- `xl:` 1280px以上の画面に適用される

が存在しますが、まるごと上書きされてしまいます。
よって既存のテーマを**拡張したい**場合は、`extend`を使います。

```js:tailwind.config.js
// デフォルトのテーマの値と組み合わせることも可能
const defaultTheme = require("tailwindcss/defaultTheme");

module.exports = {
  theme: {
    // extend プロパティの中に書く
    extend: {
      screens: {
        // xs:w-10で、480px幅以上で、w-10のスタイルが適用されるようになる
        xs: '480px'
      },
      fontFamily: {
        sans: [
          "メイリオ",
          defaultTheme.fontFamily.sans
        ]
      }
    }
  },
  ...
}
```

これで元から存在するクラスを利用できます。

```html
<!-- xs:text-* と sm:text-* が共存される -->
<button class="text-sm xs:text-base sm:text-lg">
```

すべての値をきっちり決めて管理したいわけでなければ、
既にあるTailwindのクラスを変更・拡張して使っていくことになるでしょう。

### [Variants](https://tailwindcss.com/docs/configuring-variants)

前述したとおり、Tailwindでは、定義されているクラスに対して
[レスポンシブなクラス](https://tailwindcss.com/docs/responsive-design)や、[疑似クラスを用いたクラス](https://tailwindcss.com/docs/pseudo-class-variants)がビルド時に生成されます。

- `sm:text-lg` - 画面が640px以上の時に、`text-lg`と同じスタイルが適用される
- `hover:text-lg` - マウスを乗せた時に、`text-lg`と同じスタイルが適用される

**variants**を設定すると、これらのクラスを生成するかどうかをコントロールできます。
例えば、`font-size`の規定値は、下記のようになっています。

```js:tailwind.config.js
module.exports = {
  variants: {
    fontSize: ['responsive'],
  },
  ...
}
```

上記の例だと、`'hover'`がないので、`hover:text-*`は生成されません。
生成したい場合は、こうします。

```js:tailwind.config.js
module.exports = {
  variants: {
    fontSize: ['responsive', 'hover'],
  },
  ...
}
```

また、この設定だと複合的なクラスが生成されます。

例）`sm:hover:text-lg`

>「640px以上で、マウスがのった時」に`text-lg`と同じスタイルが適用される

非常に便利です。

が、その一方で、組み合わせによってはクラスが増え、ファイルサイズが大きくなります。

そこに対する考慮があってか、`hover`や`focus`については、既定で適用されていないクラスが多いです。

規定値については、下記で確認してください。

https://tailwindcss.com/docs/configuring-variants#default-variants-reference

#### カスタム variants

例えば、下記のようにカスタムのvariantsを設定することもできます。
（プラグインについては後述します。）

```js:tailwind.config.js
module.exports = {
  variants: {
    fontSize: ['custom'],
  },
  plugins: [
    // カスタムのvariants追加
    function({ addVariant, e }) {
      addVariant("custom", ({ modifySelectors, separator }) => {
        modifySelectors(({ className }) => {
          // .custom:some-classとなる
          return `.${e(`custom${separator}${className}`)}`;
        });
      });
    },
  ]
  ...
}
```

こうすると、下記のようなCSSが生成されます。

```css
.text-lg { font-size: 1.125rem; }

.custom\:text-lg { font-size: 1.125rem; }
```

また、これらは順序の通りに生成されます。

```js:tailwind.config.js
module.exports = {
  variants: {
    fontSize: ['custom', 'hover'],
  },
  ...
}
```

```css:custom,hoverの順に生成されている
.text-lg { font-size: 1.125rem; }

.custom\:text-lg { font-size: 1.125rem; }

.hover\:text-lg:hover { font-size: 1.125rem; }
```

では、下記のような順序にしたいときには、どうするのでしょうか？

```css
.custom\:text-lg { font-size: 1.125rem; }

/* 何もついていないクラスをcustomより優先させたい */
.text-lg { font-size: 1.125rem; }

.hover\:text-lg:hover { font-size: 1.125rem; }
```

`text-lg`のような無印クラスは`default` variantsになります。
よって、

```js:tailwind.config.js
module.exports = {
  variants: {
    fontSize: ['custom', 'default', 'hover'],
  },
  ...
}
```

とできます。

### プラグインの作成

プラグインを追加することで、独自のクラスを追加することができます。
例えば、`sample-class`というクラスを追加したい場合は、下記のようにします。

```js:tailwind.config.js
module.exports = {
  plugins: [
    function({ addUtilities }) {
      const newUtilities = {
        ".sample-class": {
          // CSS-in-JS 構文になる
          backgroundColor: "red"
        }
      };

      addUtilities(newUtilities);
    }
  ]
};
```

`plugins`プロパティに、関数を追加するだけで、プラグインを定義することができます。

これにより、**サードパーティのプラグインの開発・利用**ができます。

[実際に作る際の例を記事にしてみました。](https://qiita.com/zzzzz/items/067434af65a5d121742d)

そのほかにも、カスタムvariantsを追加したり、
themeへアクセスして、クラスを動的に生成させることなどができます。

全部書いてると、長すぎて死にそうなんで、
詳しくは、こちらの公式ページを参照してください。

https://tailwindcss.com/docs/plugins

恐らく、`addUtilities`と`addComponents`、`addBase`の違いなど
若干の混乱ポイントがあるので、その際は[こちら](#base)を見て頂くといいかもしれません。

### tailwind.config.js その他のオプション

#### [Prefix](https://tailwindcss.com/docs/configuration/#prefix)

各クラスのプリフィクスを定義できます。

`text-lg` -> `x-text-lg`

```js:tailwind.config.js
module.exports = {
  prefix: 'x-',
}
```

ただし、下記のように書いたクラスには適用されません。
（プラグインで作ったクラスにはちゃんと付きます。）

```css:styles.css
@tailwind base;
@tailwind components;
@tailwind utilities;

.my-class { ... }
```

結果：

```css:output.css
.my-class { ... }

/* プラグインで追加した場合 */
.x-custom-class { ... }
```

#### [Important](https://tailwindcss.com/docs/configuration/#important)

`true`にすることで、すべてのクラスに`!important`が付きます。

```js:tailwind.config.js
module.exports = {
  important: true,
}
```

結果：

```css
.text-lg { 
  font-size: 1.125rem !important;
}
```

他のCSSと混在する際に、使うかもしれません。

#### [Seperator](https://tailwindcss.com/docs/configuration/#separator)

variantsを利用する際の、区切り文字を設定できます。

```js:tailwind.config.js
module.exports = {
  separator: "_",
}
```

結果：

```css
.hover_text-lg:hover { 
  font-size: 1.125rem !important;
}
```

公式によると、Pug等のテンプレートエンジンへの対応らしいです。

#### [Core Plugins](https://tailwindcss.com/docs/configuration/#core-plugins)

ユーティリティの有効・無効を定義できます。

下記のようにすることで、fontSizeのクラスが出力されなくなります。

```js:tailwind.config.js
module.exports = {
  corePlugins: {
    fontSize: false,
  }
}
```

逆にfontSizeのみにしたいときは、こうします。

```js:tailwind.config.js
module.exports = {
  corePlugins: [
    "fontSize"
  ]
}
```

これらを用いることで、ファイルサイズを調整できます。

後述しますが、Tailwindの中で、「Preflight」と呼ばれている部分があります。
Core Pluginは、Preflightを無効にしたい際にも利用可能です。

```js:tailwind.config.js
module.exports = {
  corePlugins: {
    preflight: false,
  }
}
```

設定可能なプロパティは、下記をご覧ください。

https://tailwindcss.com/docs/configuration/#core-plugins

## ディレクティブ

Tailwindでは、ディレクティブによるカスタマイズをすることも可能です。

ディレクティブは、CSSの中で`@xxxx`というふうに使用することがきでます。

```css:例
@tailwind base;
```

ここでは、いくつかのディレクティブを紹介していきます。

### `@tailwind`

実は、Tailwind CSSはいくつかのセクションに分かれています。

- [base](#base)
- [components](#components)
- [utilities](#utilities)
- [screens](#screens)

これらを読み込むタイミングを指定するのが`@tailwind`です。

最初に作成したCSSファイルを見てみましょう。
base -> components -> utilitiesの順になります。

```css:styles.css
@tailwind base;

@tailwind components;

@tailwind utilities;
```

では、それぞれのセクションについて説明していきます。

#### base

CSS Resetなど、すべてのベースとなるスタイルが定義されています。

プラグインの、`addBase`ではこのセクションへのクラスの追加ができます。

##### Preflight

`base`に含まれる、CSS Reset（normalize.css + 独自拡張らしいです）などが行われる部分を指します。
その為、CSS Resetを上書きするには、下記のようにします。

```css:styles.css
@tailwind base;

/** baseの後に書く **/
button { ... }

@tailwind components;

@tailwind utilities;
```

他にもプラグインを用いる方法などいろいろあります。

https://tailwindcss.com/docs/adding-base-styles/

#### components

コンポーネントクラスが集まっています。
コンポーネントクラスとは、`.button`のようなものです。

現在Tailwindが提供しているコンポーネントクラスは、`.container`クラスのみです。

自作コンポーネントクラスの追加は、プラグインの[addComponents関数](https://tailwindcss.com/docs/plugins/#adding-components)によってできます。

ただ、あまり複雑なコンポーネントをCSSのみで作成することは公式が推奨していません。
ReactやVue.jsを用いることを推奨しています。

#### utilities

`.flex`や`.opacity-0`などが含まれています。

Tailwindの大部分を占めるものになります。

プラグインでは、`addUtilities`により追加ができます。

#### screens

レスポンシブvariantsによるメディアクエリの記述は、既定ではファイルの末尾につきます。

`@tailwind screens`により、メディアクエリに関する記述の位置を、移動させることができます。

```css:styles.css
@tailwind base;

/** メディアクエリを含んだクラス（.sm\:font-boldなど）が最初に来る **/
@tailwind screens;

@tailwind components;

@tailwind utilities;
```

ただ基本的には、特定のブレークポイントに対するクラスを追加した場合、そちらを優先すべきでしょうから、そこまで位置を変更する需要はないかもしれません。

### `@apply`

classを複合した新しいクラスを作成することができます。

例えば、

```css
.btn {
  @apply font-bold py-2 px-4 rounded;
}
```

のようにして、ボタンに関する記述を一つにまとめることができます。
使いどころとしては、コンポーネント内で無尽蔵にクラスを書くよりも、ある程度CSSでまとめてから使いたい時でしょうか。

```vue:そのまま使う
<template>
  <button class="font-bold py-2 px-4 rounded"></button>
</template>
```

```vue:ある程度まとめて書く
<template>
  <button class="btn"></button>
</template>

<style>
  .btn {
    @apply font-bold py-2 px-4 rounded;
  }
</style>
```

BEM記法でコンポーネントクラスを使う際などに活躍しそうですね。

注意点としては、レスポンシブや疑似クラスは、applyできません。

```css
.btn {
  /* これはできない */
  @apply hover:bg-white md:text-lg
}
```

### `@variants`

これは、例を見た方が早いです。

```css:こう書くと
@variants focus, hover {
  .sample { ... }
}
```

```css:こうなる
.sample { ... }

.focus\:sample:focus { ... }

.hover\:sample:hover { ... }
```

`variants`プロパティ同様、こちらも順序が適用されます。

```css:こう書くと
@variants hover, focus {
  .sample { ... }
}
```

```css:こうなる
.sample { ... }

/* hoverが先に来る */
.hover\:sample:hover { ... }

.focus\:sample:focus { ... }
```

カスタムで作ったvariantsも利用可能です。

### `@responsive`

レスポンシブ関連のディレクティブになります。
`theme.screen`プロパティからコードを生成できます。

```css:こう書くと
@responsive {
  .full-width {
    width: 100%;
  }
}
```

```css:こうなる
.full-width {
  width: 100%;
}

@media (min-width: 640px) {
  .sm\:full-width{
    width: 100%;
  }
}

@media  (min-width: 768px) {
  .md\:full-width{
    width: 100%;
  }
}

/* ...ほかのサイズについても続く */
```

### `@screen`

こちらも、レスポンシブ関連です。
`theme.screen`プロパティから任意のサイズを選択して、使うことができます。

```css:こう書くと
@screen sm {
  /* ... */
}
```

```css:こうなる
@media (min-width: 640px) {
  /* ... */
}
```

## Tailwind ファンクション

最後に、ファンクションを紹介しておきます。

### `@theme`

`theme`プロパティで定義している値にアクセスできます。

```css:こう書くと
.header {
  font-size: theme('fontSize.lg');
}
```

```css:こうなる
.header {
  font-size: 1.125rem;
}
```

以上が、カスタマイズに関する部分のざっくりとした説明になります。

[公式サイト](https://tailwindcss.com/)を見て頂ければ、より多くの情報が得られるかと思います。

是非、Tailwind CSSを始めてみましょう。

## さいごに

[**v1.0.1 Stable Release**](https://tailwindcss.com/docs/release-notes)

この記事は、**v1.0.1**（安定版）が出たのを機に書きました。
なので、v1.0.1の前提で書いているので、以前のバージョンを使っている方からすると、少し違って感じるかもしれません。

また、こうしてみると、他のCSS Frameworkとは全く毛色が違うことがわかります。
ですが、決して競合するものではなく、併せて使うのはかなり有意義だと思います。
正直、CSSに対する知識がないと、使うのは厳しいかもしれませんが、
BootstrapやMaterial系のコンポーネントを使う場合でも、細かい調整には必ずCSSの知識が必要です。
他のフレームワークと比較することはあまり意味がなく、
そのフレームワークの特色を活かせるかが肝なので、開発に見合ったものを選択するといいと思います。

これまた余談ですが、[公式サイトのランディングページ](https://tailwindcss.com)で、
スクロールにより、シームレスにドキュメントに入っていくのは気持ちよさを感じます。

デザインがそうさせているのですから、Tailwindの作者がどれだけデザインを大事にしているかわかるでしょう。

ただ、Tailwind自体は、「良いデザインを作ること」とは直接関係がありません。
あくまで、デザインシステムを構築するためのユーティリティを提供するものだと思っています。
同じような思想を持ち、バニラのCSSを取り扱ってきた方はいると思います。
ただ、それら管理手法をチームや組織内で統一する目的にTailwindを使用するのは有意義かと思います。

~~あとこんな記事書くくらいなら、Tailwind CSSの日本語化に貢献しようかとも思うんですが、いかんせん英語力も日本語力も自信が無い為、手を出していません。~~

~~ドキュメントの日本語化をされている方は、どのくらい英語に詳しいのだろうかと、時々思います。~~

どうやら、Tailwindはドキュメントの多言語翻訳をするつもりが無いらしいです。

[メンテナンスが大変なので、しないとおっしゃっています。](https://github.com/tailwindcss/tailwindcss/issues/134#issuecomment-342812407)

あと、[Gridサポートとかもしない](https://github.com/tailwindcss/tailwindcss/issues/32#issuecomment-412153657)らしいです。

拡張しやすいように作ったのだから、好きに拡張してくれと言っています。

そんなこんなで、長くなりましたが、これを機にTailwind CSSを使って、カスタムでかっこいいデザインを自前で作ったり、自分でCSS Frameworkを公開する際の基盤にしてみてはと思います。

ご精読ありがとうございました。