`@apply` がCSS Mixins仕様のダッシュ識別子を素通しするよう変更

tailwindlabs/tailwindcss

Tailwind CSS v4において、@apply にCSS Custom Functions and Mixins仕様のダッシュ識別子--my-mixin 形式)が渡された場合、Tailwindのユーティリティとして解釈せずそのまま出力するよう変更されました。これにより、ネイティブCSSミックスインとTailwindの @apply が共存できるようになります。

背景

CSS Custom Functions and Mixins仕様では、@apply にダッシュ識別子(-- で始まる識別子)を渡すことでネイティブミックスインを適用する構文が定義されています。しかし、Tailwindのコンパイラはこのダッシュ識別子をユーティリティとして解釈しようとしてコンパイルに失敗していました。

#19422 では、-- で始まる識別子をTailwindが知らない場合、ブラウザや互換レイヤーが処理できるようそのまま素通しすべきであると報告されています。ミックスイン仕様は @apply というルール名を共有しているため、Tailwind側での明示的なハンドリングが必要でした。

技術的な変更

apply.tsast.ts の2ファイルに変更が加えられ、ダッシュ識別子の検出と適切なルーティングが実装されました。

packages/tailwindcss/src/apply.ts では、@apply のパラメータを走査する際に識別子を normalIdents(通常のユーティリティ)と dashedIdents(ダッシュ識別子)の2つのリストに振り分けるよう変更されました。

変更前:

for (let [idx, part] of parts.entries()) {
  if (idx % 2 === 0) candidateOffsets[part] = offset
  offset += part.length
}

変更後:

let normalIdents: string[] = []
let dashedIdents: string[] = []

for (let [idx, part] of parts.entries()) {
  if (idx % 2 === 0) {
    if (part[0] === '-' && part[1] === '-') {
      dashedIdents.push(part)
    } else {
      normalIdents.push(part)
    }
    candidateOffsets[part] = offset
  }
  offset += part.length
}

振り分けの結果に応じて、以下の3つのパスで処理されます:

  • dashedIdents のみ: CSSミックスインとみなし、WalkAction.Skip を返して処理をスキップ(そのまま出力)
  • dashedIdentsnormalIdents が混在: エラーをスローし、ユーザーにルールを分離するよう促す
  • normalIdents のみ: 従来どおりTailwindユーティリティとして処理

packages/tailwindcss/src/ast.ts では、ASTの最適化処理において @apply ルールが保持されるよう変更されています。

変更前後:

// 変更前
copy.name === '@import'

// 変更後
copy.name === '@import' ||
copy.name === '@apply'

この変更により、ダッシュ識別子のみを持つ @apply ルールがAST最適化フェーズで除去されず、出力CSSに保持されます。

設計判断

ミックスインとユーティリティの混在を意図的に禁止する設計 が採用されました。

以下のような混在した記述はすべてエラーになります:

.foo {
  /* 以下はすべて無効 */
  @apply --my-mixin underline;
  @apply --my-mixin() underline;
  @apply underline --my-mixin;
  @apply underline --my-mixin();
}

この制約は、1つの @apply ルールがTailwindのコンパイルパスとブラウザのネイティブ処理パスの両方を同時に経由することによる不整合を防ぐための判断です。混在させたい場合はルールを分離することが求められます。

なお、PRのコメントにあるとおり、Lightning CSSがこの構文にまだ対応していないため、プロダクションビルドでは正しいコードが生成されないケースがあります。テストコードにも TODO コメントとして明記されており、Lightning CSS側の対応を待ちながら段階的に解消される方針です。

まとめ

この変更は、将来のネイティブCSS機能との共存を見据えた前方互換性への対応です。ダッシュ識別子という明確な識別子プレフィックスを利用してTailwindの処理対象を区別し、エラーメッセージで混在を禁止することで、仕様と実装の境界を明確に定義しています。

記事メタデータ

Generated by:
Claude Sonnet 4.6 for DiffDaily
LLM Trace:
596128e4

この記事はAIによって自動生成されています。内容の正確性については、必ずソースコードやPRを確認してください。

品質レビュー結果

Review Status:
承認済み
Review Count:
1回
Reviewed by:
Gemini 2.5 Pro for DiffDaily

Review Criteria:

記事構成 ✓ PASS

Title, Context, Technical Detailの存在と明確さ

記事全体の構成が「総論→各論→結論」の3部構成に準拠しています。リード文で要旨を述べ、背景、技術詳細、設計判断を各論として展開し、最後に意義をまとめるという模範的な構成です。

カスタムMarkdown構文 ✓ PASS

シンタックスハイライト・GitHubリンク記法の正確性

ファイル名付きのシンタックスハイライト(```typescript:path/to/file.ts)およびGitHubのPR/Issueへのリンク記法([#123](URL))が正しく使用されています。

対象読者への適合性 ✓ PASS

エンジニア向けの適切な技術レベルと表現

Tailwind CSSのコンパイラ内部の変更という専門的な内容を、エンジニア向けに過不足なく解説しており、対象読者に完全に適合しています。

パラグラフ・ライティング ✓ PASS

トピックセンテンス・1段落1トピック・段落長

各セクションが総論から各論への流れで構成され、各段落はトピックセンテンスで始まっています。1段落1トピックの原則も守られており、可読性が非常に高いです。

Diff内容との照合 ✓ PASS

コードブロックとDiff内容の一致

記事内で引用されている`apply.ts`および`ast.ts`のコードは、提供されたDiff情報と完全に一致しています。ファイル名も正確です。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

「ダッシュ識別子(dashed idents)」「CSS Custom Functions and Mixins仕様」「AST」などの技術用語が、文脈に沿って正確に使用されています。

説明の技術的正確性 ✓ PASS

技術的主張の正確性と論理性

コード変更の意図(ダッシュ識別子と通常ユーティリティの振り分け、AST最適化での`@apply`保持)についての説明は、技術的に正確で論理的です。

事実の突合 ✓ PASS

PR情報による主張の裏付け(ハルシネーション検出)

記事内のすべての主張(ネイティブCSSミックスイン仕様との関連、ユーティリティとの混在禁止、Lightning CSSの未対応状況など)は、PRのDescriptionで完全に裏付けられています。ハルシネーションは検出されませんでした。

数値・固有名詞の確認 ✓ PASS

PR番号・コミットID・バージョン等の正確性

PR番号(#19427)、Issue番号(#19422)などの数値や固有名詞はすべて正確に記載されています。

タイトル・説明との一致 ✓ PASS

記事タイトル・説明とPR内容の一致

記事のタイトルはPR「Allow `@apply` to be used with CSS mixins」の内容をより具体的に、かつ正確に表現しており、主題の不一致はありません。

外部知識の正確性 ✓ PASS

PRに記載のない外部知識(LTS、サポート状況など)の不使用

記事に含まれる情報はすべてPR情報(Description、Diff)に基づいており、PRに記載のないバージョン情報やリリース日程などの外部知識の追加はありません。

時間表現の正確性 ✓ PASS

時間表現がPR情報と一致しているか

PR内の「does not yet support」という表現を「まだ対応していない」と正確に訳出しており、時間表現の歪曲はありません。