Tailwind v4でユーティリティクラスが共有CSSに負ける理由
モノレポの共有CSSにカスタムクラス(例: .tool-card { padding: ... })を置き、アプリ側で pl-10 を付けて上書きしようとしたら効かなかった。詳細度は同じクラス1個なのに、なぜか共有CSS側が勝つ。
原因はカスケードレイヤー
Tailwind v4はユーティリティを @layer utilities の中に出力する。一方、共有CSSファイルに書いた普通のクラスはどのレイヤーにも属さない(unlayered)CSSになる。
CSSカスケードレイヤーの仕様では、レイヤー外のスタイルはすべてのレイヤー内スタイルより優先される。詳細度の比較はレイヤーが同じときにしか行われないので、pl-10(レイヤー内)がどれだけ後から読み込まれても、レイヤー外の .tool-card のパディングには勝てない。
/* 共有CSS(レイヤー外)→ 常に勝つ */
.tool-card {
padding-left: 1.5rem;
}
/* Tailwindが生成(@layer utilities内)→ 負ける */
@layer utilities {
.pl-10 {
padding-left: 2.5rem;
}
}対処
選択肢は3つ。
- inline styleで上書きする:
style={{ paddingLeft: "2.5rem" }}。inline styleはレイヤーに関係なく勝つ。ピンポイントの上書きならこれが一番手っ取り早い - 共有CSS側を
@layer components { ... }に入れる:utilitiesレイヤーより先に宣言されたレイヤーになるため、ユーティリティで上書きできるようになる。ただし共有パッケージの構造変更が必要 - 上書き前提の設計をやめる: そもそも共有クラスとユーティリティで同じプロパティを取り合わない
共有CSSを気軽にレイヤー化できない事情がある場合、実務的には1のinline styleに落ち着く。
まとめ
- Tailwind v4のユーティリティは
@layer utilities内 → レイヤー外の普通のCSSに必ず負ける - 詳細度の問題ではなくカスケードレイヤーの仕様
- ピンポイント上書きはinline styleが確実