ブログ一覧

Tailwind v3 の PostCSS が第三者のビルド済み CSS を壊す — @layer の解釈衝突と v4(@tailwindcss/vite)移行

Astro サイトに Tailwind CSS v3 を PostCSS 経由(postcss.config.cjs + tailwind.config.cjs)で導入したところ、自分のコードには一切触れていない管理画面が 500 を返すようになり、本番ビルドも通らなくなるという現象に当たりました。

サイトは管理画面同梱型の CMS フレームワーク上に構築していて、管理画面の CSS はフレームワークがビルド済みの完成品として持っています。壊れたのはそこです。

本記事では、Tailwind v3 の PostCSS 構成が「プロジェクトを通るすべての CSS」を処理してしまう問題と、@layer の解釈衝突という壊れ方、そして Tailwind v4(@tailwindcss/vite)への移行による解決、あわせて v3 → v4 で実際に必要だったクラス名の書き換えをまとめます。

前提: Astro + Vite のプロジェクトで確認。Tailwind v3 の PostCSS 構成と、ネイティブの CSS カスケードレイヤー(@layer)を使う第三者 CSS が同居する構成全般で起こります。

なぜ他人の CSS が壊れるのか

PostCSS の設定ファイル(postcss.config.cjs)はプロジェクト全体に効きます。Vite のパイプラインを通る CSS は、自分が書いた global.css だけでなく、node_modules 由来のビルド済み CSS も含めて、全部が PostCSS プラグイン(= Tailwind v3)を通過します。

ここで衝突するのが @layer です。

  • CSS 標準@layerカスケードレイヤー。モダンな UI ライブラリのビルド済み CSS は普通に使っています(@layer base { ... } など)
  • Tailwind v3 は同じ @layer自前のディレクティブとして解釈します。v3 にとって @layer base は「@tailwind base で展開される場所に挿入する宣言」であり、対応する @tailwind base がないファイルに現れると、こういうエラーで止まります
`@layer base` is used but no matching `@tailwind base` directive is present.

つまり、標準 CSS として完全に正しい第三者のファイルが、Tailwind v3 の PostCSS を通った瞬間に不正になるわけです。開発サーバーでは管理画面の CSS 配信が 500 になり、本番ビルドはこのエラーで落ちました。

v3 でこれを回避しようとすると「PostCSS の対象からそのファイルを外す」方向の設定をひねり出すことになり、かなり不毛です。

解決: Tailwind v4 の Vite プラグインに移行する

Tailwind v4 はこの問題の根本部分が設計から変わっています。

  • @layer自前解釈をやめ、ネイティブのカスケードレイヤーをそのまま使うようになった。第三者 CSS の @layer base はただの標準 CSS として素通りする
  • 導入も PostCSS 設定ではなく Vite プラグイン@tailwindcss/vite)になり、プロジェクト全体の CSS を無差別に巻き込まない

移行はファイル 3 つの置き換えで済みました。

// astro.config.mjs
import tailwindcss from "@tailwindcss/vite";

export default defineConfig({
	vite: {
		plugins: [tailwindcss()],
	},
});
/* global.css — v3 の @tailwind 3行が @import 1行になる */
@import "tailwindcss";
@plugin "@tailwindcss/forms";

postcss.config.cjstailwind.config.cjs は削除します(v4 は設定も CSS 内の @theme に寄せる方針で、シンプルな構成なら設定ファイル自体が不要です)。これで管理画面の 500 も本番ビルドのエラーも解消しました。

v3 → v4 で実際に書き換えたクラス名

v4 は既存クラスの一部を改名しています。移行で実際に引っかかったものだけ挙げます(網羅は公式アップグレードガイドを参照)。

  • bg-gradient-to-r など → bg-linear-to-r
  • rounded(無印) → rounded-sm
  • shadow-smshadow-xs
  • backdrop-blur-smbackdrop-blur-xs
  • !leading-tight(important 前置) → leading-tight!接尾辞に変更)

サイズ系は「一段ずれた」(旧 sm が新 xs に相当)と覚えると楽です。important 修飾子の前置 → 接尾辞は grep で機械的に拾えます。

なお移行後に旧環境と getComputedStyle で突き合わせたところ、色が rgb → oklab 表記に変わっている箇所がありますが、これは v4 が内部のカラー処理を近代化した結果の表記差で、実際の色は同一でした。ピクセル比較で「色が変わった!」と焦らないように。

Tailwind 移行の話としては、そもそも Vuetify から Tailwind に乗り換えたときの記録「さようならVuetify。ようこそTailwind CSS」、CSS 最適化全般は「CSSの最適化アプローチ」も参考にどうぞ。

まとめ

  • Tailwind v3 の PostCSS 構成は、node_modules のビルド済み CSS を含むすべての CSS を処理対象にする
  • v3 は @layer を自前ディレクティブとして解釈するため、ネイティブのカスケードレイヤーを使う標準準拠の第三者 CSS がエラーになる
  • Tailwind v4 + @tailwindcss/vite へ移行すると、ネイティブ @layer は素通りになり衝突が消える。設定ファイルも減る
  • v4 のクラス改名(bg-linear-to-*、サイズ一段ずれ、important 接尾辞化)は grep で機械的に対応できる。oklab 表記への変化は見た目同一

参考リンク