← 記事一覧へ

Tailwind v4でユーティリティクラスが共有CSSに負ける理由

csstailwind

モノレポの共有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つ。

  1. inline styleで上書きする: style={{ paddingLeft: "2.5rem" }}。inline styleはレイヤーに関係なく勝つ。ピンポイントの上書きならこれが一番手っ取り早い
  2. 共有CSS側を @layer components { ... } に入れる: utilities レイヤーより先に宣言されたレイヤーになるため、ユーティリティで上書きできるようになる。ただし共有パッケージの構造変更が必要
  3. 上書き前提の設計をやめる: そもそも共有クラスとユーティリティで同じプロパティを取り合わない

共有CSSを気軽にレイヤー化できない事情がある場合、実務的には1のinline styleに落ち着く。

まとめ

  • Tailwind v4のユーティリティは @layer utilities 内 → レイヤー外の普通のCSSに必ず負ける
  • 詳細度の問題ではなくカスケードレイヤーの仕様
  • ピンポイント上書きはinline styleが確実