tailwind.config.jsファイルのcontentセクションでは、HTMLテンプレート、JavaScriptコンポーネント、およびTailwindクラス名を含むその他のすべてのソースファイルのパスを設定します。

tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    './pages/**/*.{html,js}',
    './components/**/*.{html,js}',
  ],
  // ...
}

このガイドでは、プロジェクトに必要なすべてのCSSをTailwindが生成できるようにするために知っておくべきすべての事項を説明します。


ソースパスの設定

Tailwind CSSは、すべてのHTML、JavaScriptコンポーネント、およびその他のテンプレートファイルをクラス名でスキャンし、それらのスタイルに対応するすべてのCSSを生成することによって機能します。

Tailwindがあなたに必要なすべてのCSSを生成するためには、あなたのプロジェクト内のTailwindクラス名を含むすべての単一のファイルを知る必要があります。

設定ファイルのcontentセクションですべてのコンテンツファイルのパスを設定します。

tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    './pages/**/*.{html,js}',
    './components/**/*.{html,js}'
  ],
  // ...
}

パスはglobパターンとして構成されているため、大量の設定なしにプロジェクト内のすべてのコンテンツファイルに簡単に一致させることができます。

  • スラッシュと隠しファイルを除くすべてに一致するには、*を使用します。
  • ゼロ個以上のディレクトリに一致するには、**を使用します。
  • {}の間にコンマ区切りの値を使用して、オプションのリストと一致させます。

Tailwindは、内部でfast-globライブラリを使用しています。サポートされているその他のパターン機能については、ドキュメントを確認してください。

パスは、tailwind.config.jsファイルではなく、プロジェクトのルートからの相対パスです。したがって、tailwind.config.jsファイルがカスタムの場所にある場合は、プロジェクトのルートを基準にしてパスを記述する必要があります。

パターンに関する推奨事項

最高のパフォーマンスを実現し、誤検出を回避するには、コンテンツ構成をできるだけ具体的にしてください。

このような非常に広範なパターンを使用すると、Tailwindはnode_modulesのコンテンツもスキャンします。これはおそらく望ましいものではありません。

非常に広範なパターンを使用しないでください。

tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    './**/*.{html,js}',
  ],
  // ...
}

プロジェクトのルートにあるスキャンする必要のあるファイル(多くの場合、index.htmlファイル)がある場合は、他のパターンをより具体的にするために、そのファイルを個別にリストします。

コンテンツパターンを具体的にします。

tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    './components/**/*.{html,js}',
    './pages/**/*.{html,js}',
    './index.html',
  ],
  // ...
}

一部のフレームワークでは、メインのHTMLエントリポイントが残りのテンプレートとは異なる場所(多くの場合public/index.html)に隠されているため、そのファイルにTailwindクラスを追加する場合は、構成に含めるようにしてください。

該当する場合は、HTMLエントリポイントを含めることを忘れないでください。

tailwind.config.js
module.exports = {
  content: [
    './public/index.html',
    './src/**/*.{html,js}',
  ],
  // ...
}

HTMLを操作してクラスを追加するJavaScriptファイルがある場合は、それらも必ず含めてください。

tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    // ...
    './src/**/*.js',
  ],
  // ...
}
src/spaghetti.js
// ...
menuButton.addEventListener('click', function () {
  let classList = document.getElementById('nav').classList
  classList.toggle('hidden')
  classList.toggle('block')
})
// ...

また、CSSファイルをスキャンしないことも重要です。Tailwindを構成して、クラス名が使用されているテンプレートをスキャンし、Tailwindが生成しているCSSファイルをスキャンしないでください。

コンテンツ構成にCSSファイルを含めないでください。

tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    './src/**/*.css',
  ],
  // ...
}

クラス検出の詳細

Tailwindがソースコードをクラス名でスキャンする方法は、意図的に非常に単純です。実際に記述されている言語でコードを解析または実行するのではなく、正規表現を使用して、クラス名である可能性のあるすべての文字列を抽出します。

たとえば、すべての潜在的なクラス名文字列が個別に強調表示されたHTMLを次に示します。

<div class="md:flex">
  <div class="md:flex-shrink-0">
    <img class="rounded-lg md:w-56" src="/img/shopping.jpg" alt="Woman paying for a purchase">
  </div>
  <div class="mt-4 md:mt-0 md:ml-6">
    <div class="uppercase tracking-wide text-sm text-indigo-600 font-bold">
      Marketing
    </div>
    <a href="/get-started" class="block mt-1 text-lg leading-tight font-semibold text-gray-900 hover:underline">
      Finding customers for your new business
    </a>
    <p class="mt-2 text-gray-600">
      Getting a new business off the ground is a lot of hard work.
      Here are five ideas you can use to find your first customers.
    </p>
  </div>
</div>

class="..."属性への検索を制限するだけではありません。たとえば、メニューを切り替えるためのJavaScriptなど、クラスをどこでも使用できるからです。

spaghetti.js
<script>
  menuButton.addEventListener('click', function () {
    let classList = document.getElementById('nav').classList
    classList.toggle('hidden')
    classList.toggle('block')
  })
</script>

この非常にシンプルなアプローチを使用することにより、TailwindはJSXなどのプログラミング言語と非常に信頼性の高い方法で連携します。

Button.jsx
const sizes = {
  md: 'px-4 py-2 rounded-md text-base',
  lg: 'px-5 py-3 rounded-lg text-lg',
}

const colors = {
  indigo: 'bg-indigo-500 hover:bg-indigo-600 text-white',
  cyan: 'bg-cyan-600 hover:bg-cyan-700 text-white',
}

export default function Button({ color, size, children }) {
  let colorClasses = colors[color]
  let sizeClasses = sizes[size]

  return (
    <button type="button" className={`font-bold ${sizeClasses} ${colorClasses}`}>
      {children}
    </button>
  )
}

動的なクラス名

Tailwindがクラス名を抽出する方法の最も重要な意味は、ソースファイルに完全な途切れていない文字列として存在するクラスのみを見つけるということです。

文字列補間を使用したり、部分的なクラス名を連結したりすると、Tailwindはそれらを見つけないため、対応するCSSは生成されません。

クラス名を動的に構築しないでください。

<div class="text-{{ error ? 'red' : 'green' }}-600"></div>

上記の例では、文字列text-red-600およびtext-green-600は存在しないため、Tailwindはこれらのクラスを生成しません。

代わりに、使用しているクラス名が完全に存在することを確認してください。

常に完全なクラス名を使用してください。

<div class="{{ error ? 'text-red-600' : 'text-green-600' }}"></div>

ReactやVueのようなコンポーネントライブラリを使用している場合、これはpropsを使用してクラスを動的に構築すべきではないことを意味します。

propsを使用してクラス名を動的に構築しないでください。

function Button({ color, children }) {
  return (
    <button className={`bg-${color}-600 hover:bg-${color}-500 ...`}>
      {children}
    </button>
  )
}

代わりに、ビルド時に静的に検出可能な完全なクラス名にpropsをマップします。

常にpropsを静的なクラス名にマップします。

function Button({ color, children }) {
  const colorVariants = {
    blue: 'bg-blue-600 hover:bg-blue-500',
    red: 'bg-red-600 hover:bg-red-500',
  }

  return (
    <button className={`${colorVariants[color]} ...`}>
      {children}
    </button>
  )
}

これにより、たとえば、さまざまなプロップ値をさまざまな色合いにマッピングできるという追加の利点があります。

function Button({ color, children }) {
  const colorVariants = {
    blue: 'bg-blue-600 hover:bg-blue-500 text-white',
    red: 'bg-red-500 hover:bg-red-400 text-white',
    yellow: 'bg-yellow-300 hover:bg-yellow-400 text-black',
  }

  return (
    <button className={`${colorVariants[color]} ...`}>
      {children}
    </button>
  )
}

コード内で常に完全なクラス名を使用している限り、Tailwindは常に完璧にすべてのCSSを生成します。

サードパーティライブラリとの連携

もしあなたが、(例えばSelect2のような)サードパーティのライブラリを使っていて、そのライブラリを独自のカスタムCSSでスタイリングしている場合、Tailwindの@layer機能を使わずにそれらのスタイルを書くことをお勧めします。

main.css
@tailwind base;
@tailwind components;

.select2-dropdown {
  @apply rounded-b-lg shadow-md;
}
.select2-search {
  @apply border border-gray-300 rounded;
}
.select2-results__group {
  @apply text-lg font-bold text-gray-900;
}
/* ... */

@tailwind utilities;

これにより、Tailwindはそれらのスタイルを常にCSSに含めるようになり、サードパーティライブラリのソースコードをスキャンするようにTailwindを設定するよりもずっと簡単になります。

もしあなたがTailwindでスタイリングされた再利用可能なコンポーネントのセットを作成し、それらを複数のプロジェクトでインポートしている場合、Tailwindがそれらのコンポーネントのクラス名をスキャンするように設定してください。

tailwind.config.js
module.exports = {
  content: [
    './components/**/*.{html,js}',
    './pages/**/*.{html,js}',
    './node_modules/@my-company/tailwind-components/**/*.js',
  ],
  // ...
}

これにより、Tailwindがそれらのコンポーネントに必要なすべてのCSSを生成するようになります。

もしあなたがワークスペースを持つモノレポで作業している場合、Tailwindがコンテンツファイルを見つけられるように、require.resolveを使用する必要があるかもしれません。

tailwind.config.js
const path = require('path');

module.exports = {
  content: [
    './components/**/*.{html,js}',
    './pages/**/*.{html,js}',
    path.join(path.dirname(require.resolve('@my-company/tailwind-components')), '**/*.js'),
  ],
  // ...
}

相対パスの使用

デフォルトでは、Tailwindは非絶対コンテンツパスを、tailwind.config.jsファイルではなく、現在の作業ディレクトリからの相対パスとして解決します。これは、異なるディレクトリからTailwindを実行した場合、予期しない結果につながる可能性があります。

常にtailwind.config.jsファイルからの相対パスとして解決するには、content設定にオブジェクト記法を使用し、relativeプロパティをtrueに設定してください。

tailwind.config.js
module.exports = {
  content: {
    relative: true,
    files: [
      './pages/**/*.{html,js}',
      './components/**/*.{html,js}',
    ],
  },
  // ...
}

これは、フレームワークの次のメジャーバージョンでデフォルトの動作になる可能性があります。

生のコンテンツの設定

何らかの理由で、Tailwindにファイルのコンテンツではなく、生のコンテンツをスキャンするように設定する必要がある場合は、パスの代わりにrawキーを持つオブジェクトを使用してください。

tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    './pages/**/*.{html,js}',
    './components/**/*.{html,js}',
    { raw: '<div class="font-bold">', extension: 'html' },
  ],
  // ...
}

これには有効なユースケースはあまりありません。通常はセーフリスティングが本当に必要なものです。


クラスのセーフリスティング

ファイルサイズを最小限に抑え、開発体験を向上させるために、Tailwindにどのクラスを生成するかを指示するために、できる限りcontent設定に依存することを強くお勧めします。

セーフリスティングは最後の手段であり、特定のコンテンツのクラス名をスキャンすることが不可能な場合にのみ使用する必要があります。このような状況はまれであり、この機能がほとんど必要になることはありません。

コンテンツファイルに存在しない特定のクラス名をTailwindに生成させたい場合は、safelistオプションを使用してください。

tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    './pages/**/*.{html,js}',
    './components/**/*.{html,js}',
  ],
  safelist: [
    'bg-red-500',
    'text-3xl',
    'lg:text-4xl',
  ]
  // ...
}

この機能が役立つ例の1つは、サイトでユーザーが生成したコンテンツを表示する場合で、ユーザーが自分のサイトのソースファイルに存在しない可能性のあるTailwindクラスの制約されたセットをコンテンツで使用できるようにしたい場合です。

正規表現の使用

Tailwindは、多くのクラスをセーフリストする必要がある状況に対応するために、パターンベースのセーフリスティングをサポートしています。

tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    './pages/**/*.{html,js}',
    './components/**/*.{html,js}',
  ],
  safelist: [
    'text-2xl',
    'text-3xl',
    {
      pattern: /bg-(red|green|blue)-(100|200|300)/,
    },
  ],
  // ...
}

パターンは、/bg-red-.+/のようなベースユーティリティ名に対してのみ一致し、/hover:bg-red-.+/のようにバリアント修飾子が含まれている場合は一致しません。

一致したクラスのバリアントを強制的にTailwindに生成させたい場合は、variantsオプションを使用して含めてください。

tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    './pages/**/*.{html,js}',
    './components/**/*.{html,js}',
  ],
  safelist: [
    'text-2xl',
    'text-3xl',
    {
      pattern: /bg-(red|green|blue)-(100|200|300)/,
      variants: ['lg', 'hover', 'focus', 'lg:hover'],
    },
  ],
  // ...
}

クラスの破棄

Tailwindはコンテンツ内のクラス名を検出するために非常に単純なアプローチを使用しているため、実際には必要のないクラスが生成されていることに気づくかもしれません。

たとえば、このHTMLは、containerクラスが実際には使用されていなくても、生成されます。

<div class="text-lg leading-8 text-gray-600">
  Every custom pool we design starts as a used shipping container, and is
  retrofitted with state of the art technology and finishes to turn it into
  a beautiful and functional way to entertain your guests all summer long.
</div>

また、Tailwindのクラスが既存のCSSと競合する場合に、Tailwindクラスにすべてプレフィックスを付けるほどではない場合に、特定のクラスがTailwindによって生成されないようにすることもできます。

このような状況では、blocklistオプションを使用して、コンテンツ内で検出された特定のクラスをTailwindに無視するように指示できます。

tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    './pages/**/*.{html,js}',
    './components/**/*.{html,js}',
  ],
  blocklist: [
    'container',
    'collapse',
  ],
  // ...
}

blocklistオプションは、Tailwindによって生成されるCSSにのみ影響し、自分で作成したカスタムCSSや別のライブラリからインポートしたCSSには影響しません。

safelistとは異なり、blocklistオプションは文字列のみをサポートしており、正規表現を使用してクラスをブロックすることはできません。


ソースファイルの変換

(Markdownのように)HTMLにコンパイルされる形式でコンテンツを作成している場合は、クラス名をスキャンするに、そのコンテンツをHTMLにコンパイルするのが理にかなっていることがよくあります。

特定のファイル拡張子に一致するコンテンツを変換してからクラスを抽出するには、content.transformオプションを使用します。

tailwind.config.js
const remark = require('remark')

module.exports = {
  content: {
    files: ['./src/**/*.{html,md}'],
    transform: {
      md: (content) => {
        return remark().process(content)
      }
    }
  },
  // ...
}

content.transformを使用する場合は、contentの下のトップレベルの配列としてではなく、content.filesを使用してソースパスを提供する必要があります。


抽出ロジックのカスタマイズ

特定のファイル拡張子に対するクラス名の検出にTailwindが使用するロジックをオーバーライドするには、extractオプションを使用します。

tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: {
    files: ['./src/**/*.{html,wtf}'],
    extract: {
      wtf: (content) => {
        return content.match(/[^<>"'`\s]*/g)
      }
    }
  },
  // ...
}

これは高度な機能であり、ほとんどのユーザーは必要ありません。Tailwindのデフォルトの抽出ロジックは、ほとんどすべてのプロジェクトで非常にうまく機能します。

変換と同様に、content.extractを使用する場合は、contentの下のトップレベルの配列としてではなく、content.filesを使用してソースパスを提供する必要があります。


トラブルシューティング

クラスが生成されない

Tailwindがクラスを生成しない場合は、content設定が正しく、すべての適切なソースファイルと一致していることを確認してください。

よくある間違いは、Reactコンポーネントにjsの代わりにjsxを使用している場合など、ファイル拡張子が欠落していることです。

tailwind.config.js
module.exports = {
  content: [
    './src/**/*.{html,js}',
    './src/**/*.{html,js,jsx}'
  ],
  // ...
}

または、プロジェクトの途中で、元々カバーされていなかった新しいフォルダを作成し、それを設定に追加するのを忘れていることです。

tailwind.config.js
module.exports = {
  content: [
    './pages/**/*.{html,js}',
    './components/**/*.{html,js}',
    './util/**/*.{html,js}'
  ],
  // ...
}

また、動的なクラス名を使用しようとしている可能性もあります。Tailwindは実際にソースコードを評価せず、静的な切れ目のないクラス文字列のみを検出できるため、動的なクラス名は機能しません。

クラス名を動的に構築しないでください。

<div class="text-{{ error ? 'red' : 'green' }}-600"></div>

常にコードで完全なクラス名を使用するようにしてください。

常に完全なクラス名を使用してください。

<div class="{{ error ? 'text-red-600' : 'text-green-600' }}"></div>

詳細については、動的なクラス名に関するドキュメントをお読みください。

スタイルが無限ループで再構築される

CSSが無限ループで再構築されているように見える場合、それは、ビルドツールが、PostCSSの依存関係を登録するときにglobオプションをサポートしていない可能性が高いです。

多くのビルドツール(webpackなど)はこのオプションをサポートしておらず、その結果、特定のファイルまたはディレクトリ全体を監視するように指示することしかできません。たとえば、ディレクトリ内の*.htmlファイルのみを監視するようにwebpackに指示することはできません。

つまり、CSSをビルドすることで、これらのディレクトリ内のいずれかのファイルが変更された場合、変更されたファイルがglobの拡張子と一致しない場合でも、再ビルドがトリガーされます。

tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    // With some build tools, your CSS will rebuild
    // any time *any* file in `src` changes.
    './src/**/*.{html,js}',
  ],
  // ...
}

したがって、src/**/*.htmlの変更を監視しているが、CSS出力ファイルをsrc/css/styles.cssに書き込んでいる場合、一部のツールでは無限の再ビルドループが発生します。

理想的には、コンソールでこれについて警告できますが、多くのツールは(独自のCLIツールを含め)完全に正常にサポートしており、使用しているビルドツールを確実に検出する方法はありません。

この問題を解決するには、content設定でより具体的なパスを使用し、CSSのビルド時に変更されないディレクトリのみを含めるようにしてください。

tailwind.config.js
module.exports = {
  content: [
    './src/**/*.{html,js}',
    './src/pages/**/*.{html,js}',
    './src/components/**/*.{html,js}',
    './src/layouts/**/*.{html,js}',
    './src/index.html',
  ],
  // ...
}

必要に応じて、実際のプロジェクトディレクトリ構造を調整して、CSSファイルやマニフェストファイルなどの他のビルド成果物を誤ってキャッチすることなく、テンプレートファイルをターゲットにできるようにしてください。

どうしてもコンテンツ設定やディレクトリ構造を変更できない場合は、globサポートが完全なツールでCSSを個別にコンパイルするのが最善の方法です。TailwindでCSSをコンパイルするための高速でシンプルな専用ツールであるTailwind CLIを使用することをお勧めします。

正常に動作しない

もし出力に奇妙で説明しにくい問題が発生した場合や、全く動作していないように見える場合は、ビルドツールがPostCSSの依存関係メッセージを正しくサポートしていない(または全くサポートしていない)可能性が高いです。現在、既知の例としてStencilがあります。

これらの種類の問題が発生した場合は、既存のツールにTailwindを統合しようとするのではなく、Tailwind CLIを使用してCSSを個別にコンパイルすることをお勧めします。

npm-run-allconcurrentlyのようなパッケージを使用して、以下のようにプロジェクトにスクリプトを追加することで、通常の開発コマンドと並行してCSSをコンパイルできます。

// package.json
{
  // ...
  "scripts": {
    "start": "concurrently \"npm run start:css\" \"react-scripts start\"",
    "start:css": "tailwindcss -o src/tailwind.css --watch",
    "build": "npm run build:css && react-scripts build",
    "build:css": "NODE_ENV=production tailwindcss -o src/tailwind.css -m",
  },
}

いずれにしても、既存の問題がないか確認するか、新しい問題を開いて、問題を把握し、使用しているツールとの互換性を改善できるようにしてください。