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.cjs と tailwind.config.cjs は削除します(v4 は設定も CSS 内の @theme に寄せる方針で、シンプルな構成なら設定ファイル自体が不要です)。これで管理画面の 500 も本番ビルドのエラーも解消しました。
v3 → v4 で実際に書き換えたクラス名
v4 は既存クラスの一部を改名しています。移行で実際に引っかかったものだけ挙げます(網羅は公式アップグレードガイドを参照)。
bg-gradient-to-rなど →bg-linear-to-rrounded(無印) →rounded-smshadow-sm→shadow-xsbackdrop-blur-sm→backdrop-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 表記への変化は見た目同一