# 機能設計書 41-color-mix()ポリフィル

## 概要

本ドキュメントは、Tailwind CSSにおけるcolor-mix()関数のポリフィル機能について記述する。CSS `color-mix()` 関数をサポートしていないブラウザ向けにフォールバックCSSを生成する処理の設計を定義する。

### 本機能の処理概要

color-mix()ポリフィルは、CSS `color-mix()` 関数を使用した宣言に対して、対応していないブラウザ向けの代替CSSを自動生成する機能である。

**業務上の目的・背景**：CSS `color-mix()` 関数はoklab/oklchなどの色空間でのカラーミキシングを可能にするモダンCSS機能だが、Safari 16未満やFirefoxの古いバージョンでは未サポートである。Tailwind CSSのユーティリティクラスは透明度修飾子（例：`text-red-500/50`）でcolor-mix()を使用するため、ブラウザ互換性のためにフォールバック値の自動生成が必要となる。

**機能の利用シーン**：ビルド時のAST最適化フェーズにおいて、`Polyfills.ColorMix` フラグが有効な場合に自動実行される。開発者がユーティリティクラスに透明度修飾子を使用したとき、またはカスタムCSSで `color-mix()` 関数を使用したときにフォールバックが挿入される。

**主要な処理内容**：
1. AST最適化処理（`optimizeAst`）の中で、`color-mix()` を含む宣言を収集する
2. 各宣言のcolor-mix()内で使用されるCSS変数をテーマから解決し、インライン化を試みる
3. 解決可能な場合はフォールバック値を生成し、元の宣言を `@supports` クエリで囲む
4. `currentcolor` や解決不可能な変数を含む場合は、color-mix()の第一カラー値をフォールバックとして使用する
5. 色空間をsrgbに変換してフォールバック値の互換性を確保する

**関連システム・外部連携**：テーマシステム（Theme）からCSS変数の値を解決する。ValueParserを使用してCSS値の解析・再構成を行う。

**権限による制御**：特になし。`Polyfills.ColorMix` フラグによって有効/無効が制御される。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 画面には直接関連しない。ビルドパイプラインの内部処理として動作する |

## 機能種別

計算処理（CSSフォールバック生成）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| ast | AstNode[] | Yes | 最適化対象のAST配列 | 有効なASTノードの配列であること |
| designSystem | DesignSystem | Yes | テーマ変数の解決に使用するデザインシステム | 有効なDesignSystemインスタンスであること |
| polyfills | Polyfills | No | ポリフィルフラグ（デフォルト: Polyfills.All） | Polyfills列挙型の有効な値であること |

### 入力データソース

- AST最適化パイプラインの中間状態として渡されるASTノード配列
- DesignSystemオブジェクト内のThemeインスタンス（CSS変数の解決に使用）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 変換後AST | AstNode[] | フォールバック宣言と@supportsクエリが挿入されたAST |

### 出力先

- ASTノード配列に対してインプレースで変更が適用される（optimizeAst関数の出力の一部）

## 処理フロー

### 処理シーケンス

```
1. AST走査・宣言収集フェーズ（transform関数内）
   └─ color-mix()を含む宣言をcolorMixDeclarationsマップに収集
      - @supportsブロック内の場合は収集をスキップ
      - @keyframes内の場合は収集をスキップ

2. フォールバック生成フェーズ（optimizeAst関数後半）
   └─ Polyfills.ColorMixフラグが有効な場合のみ実行
      ├─ 各colorMixDeclarationsのエントリを処理
      │   ├─ 宣言のvalueをValueParserで解析
      │   ├─ color-mix()関数ノードを走査
      │   │   ├─ var()参照をテーマから解決してインライン化
      │   │   ├─ currentcolorの検出
      │   │   └─ 解決不可能な変数の検出
      │   ├─ フォールバック値の決定
      │   │   ├─ 解決不可能/currentcolor → 第一カラー値を使用
      │   │   └─ 解決可能 → 色空間をsrgbに変換してインライン化
      │   └─ AST変換
      │       ├─ フォールバック宣言を挿入
      │       └─ 元の宣言を@supports (color: color-mix(in lab, red, red))で囲む
      └─ 完了
```

### フローチャート

```mermaid
flowchart TD
    A[開始: optimizeAst内transform] --> B{Polyfills.ColorMixが有効?}
    B -->|No| Z[スキップ]
    B -->|Yes| C{宣言にcolor-mixが含まれる?}
    C -->|No| Z
    C -->|Yes| D{@supports内?}
    D -->|Yes| Z
    D -->|No| E[colorMixDeclarationsに収集]
    E --> F[フォールバック生成フェーズ]
    F --> G[ValueParserで値を解析]
    G --> H{color-mix内にvar参照?}
    H -->|No| I[ポリフィル不要]
    H -->|Yes| J[テーマから変数を解決]
    J --> K{解決可能?}
    K -->|No| L[第一カラー値をフォールバックに使用]
    K -->|Yes| M{currentcolorを含む?}
    M -->|Yes| L
    M -->|No| N[色空間をsrgbに変換]
    N --> O[インライン化した値でフォールバック生成]
    L --> P[parent配列を変更]
    O --> P
    P --> Q[フォールバック宣言を挿入]
    Q --> R[@supportsクエリで元宣言を囲む]
    R --> S[完了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-41-01 | フォールバック条件 | color-mix()関数内でCSS変数（var()）またはcurrentcolorが使用されている場合にのみフォールバックを生成する | Polyfills.ColorMixが有効な場合 |
| BR-41-02 | @supports除外 | 既に@supports (color: color-mix(...))内にある宣言はフォールバック対象外とする | @supportsブロックのネスト検出時 |
| BR-41-03 | @keyframes除外 | @keyframes内の宣言はフォールバック対象外とする | @keyframesコンテキスト内 |
| BR-41-04 | 色空間変換 | フォールバック値の色空間をoklab/oklch/lab/lchからsrgbに変換する | 解決可能なvar参照を含む場合 |
| BR-41-05 | currentcolor処理 | currentcolorが含まれる場合、color-mix全体を第一カラー値で置換する | currentcolorの検出時 |
| BR-41-06 | 循環参照防止 | var()の解決時にseenVariablesで循環参照を検出し、解決不可能として処理する | 変数のインライン化試行時 |

### 計算ロジック

フォールバック値の生成は以下のロジックで行われる：

1. **変数解決**: `designSystem.theme.resolveValue(null, [variableName])` でCSS変数の実際の値を取得
2. **インライン化**: 解決された値でvar()参照を置換。解決された値が再びvar()の場合は再帰的に解決を試みる
3. **色空間変換**: oklab/oklch/lab/lchをsrgbに書き換え（Safari 16未満でのoklab/oklchサポート不足への対策）
4. **フォールバック構造**: `[fallback宣言] + [@supports (color: color-mix(in lab, red, red)) { [元の宣言] }]`

## データベース操作仕様

### 操作別データベース影響一覧

該当なし（メモリ上のAST操作のみ）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 変数解決失敗 | テーマに存在しないCSS変数が参照された場合 | containsUnresolvableVarsフラグを立て、第一カラー値をフォールバックとして使用 |
| - | 循環参照 | CSS変数が自身を参照する循環構造の場合 | seenVariablesで検出し、解決不可能として処理 |

### リトライ仕様

リトライは不要。処理は同期的に実行され、失敗時はグレースフルにフォールバックする。

## トランザクション仕様

該当なし（メモリ上のAST操作のみ）

## パフォーマンス要件

- AST最適化フェーズの一部として実行されるため、コンパイル全体のパフォーマンスに影響する
- DefaultMapを使用して親ノードごとにcolorMix宣言をグループ化し、効率的に処理する
- ValueParserによる値の解析は宣言単位で実行される

## セキュリティ考慮事項

該当なし（ビルド時処理であり、ユーザー入力の直接処理は行わない）

## 備考

- Polyfills列挙型はビットフラグとして定義されており、`Polyfills.All = AtProperty | ColorMix` で全ポリフィルが有効になる
- color-mix()ポリフィルは`optimizeAst`関数の後半で、@propertyポリフィルとは独立して処理される
- `@supports (color: color-mix(in lab, red, red))` クエリは、ブラウザがcolor-mix()をサポートしている場合にのみ元の宣言を適用するために使用される

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

まず、Polyfillsフラグの定義とASTノードの型を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | index.ts | `packages/tailwindcss/src/index.ts` | Polyfills列挙型の定義（41-52行目）。None/AtProperty/ColorMix/Allのビットフラグ構造 |
| 1-2 | ast.ts | `packages/tailwindcss/src/ast.ts` | AstNode型（StyleRule/AtRule/Declaration/Comment/Context）の定義（13-80行目付近） |
| 1-3 | value-parser.ts | `packages/tailwindcss/src/value-parser.ts` | ValueParserの出力ノード型（word/function/separator）の定義 |

**読解のコツ**: Polyfills列挙型はビットフラグとして定義されており、`&` 演算子で個別のフラグの有効/無効を判定する。`Polyfills.All` は全フラグの論理和。

#### Step 2: エントリーポイントを理解する

color-mix()ポリフィルのエントリーポイントは `optimizeAst` 関数内にある。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ast.ts | `packages/tailwindcss/src/ast.ts` | optimizeAst関数の開始（220-224行目）。polyfillsパラメータのデフォルト値がPolyfills.All |

**主要処理フロー**:
1. **228行目**: `colorMixDeclarations` の DefaultMap 初期化
2. **283-292行目**: transform関数内で `color-mix()` を含む宣言を収集
3. **386-388行目**: `@supports` ブロック内の場合は `supportsColorMix` コンテキストを設定
4. **519-617行目**: フォールバック生成処理の本体

#### Step 3: 宣言収集処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ast.ts | `packages/tailwindcss/src/ast.ts` | transform関数のDeclaration処理（283-292行目）。収集条件: Polyfills.ColorMixが有効 && color-mix()を含む && @supports外 && @keyframes外 |

**主要処理フロー**:
- **285-286行目**: `polyfills & Polyfills.ColorMix` でフラグチェック
- **287行目**: `node.value.includes('color-mix(')` で宣言値にcolor-mix()が含まれるかチェック
- **288行目**: `!context.supportsColorMix` で既に@supportsブロック内でないことを確認
- **289行目**: `!context.keyframes` で@keyframes内でないことを確認
- **291行目**: 親ノード配列をキーとしてDefaultMapに宣言を追加

#### Step 4: フォールバック生成処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | ast.ts | `packages/tailwindcss/src/ast.ts` | フォールバック生成の本体（519-617行目）。収集された宣言を順に処理し、フォールバック値と@supportsクエリを生成 |

**主要処理フロー**:
- **521行目**: `polyfills & Polyfills.ColorMix` の最終チェック
- **528行目**: `ValueParser.parse(declaration.value)` でCSS値をAST化
- **530-605行目**: color-mix()関数内のvar()参照を解決するウォーク処理
- **536-537行目**: `currentcolor` の検出
- **546-577行目**: var()のネスト解決（再帰的なテーマ変数解決）
- **582-590行目**: 解決不可能/currentcolorの場合は第一カラー値を使用
- **593-603行目**: 色空間をsrgbに変換
- **608-614行目**: フォールバック宣言と@supportsクエリの挿入

### プログラム呼び出し階層図

```
optimizeAst(ast, designSystem, polyfills)
    │
    ├─ transform(node, parent, context, depth)  [AST走査]
    │      ├─ 宣言のcolor-mix()チェック (283-292行目)
    │      │     └─ colorMixDeclarations.get(parent).add(node)
    │      └─ @supportsコンテキスト設定 (386-388行目)
    │
    └─ フォールバック生成 (519-617行目)
           ├─ ValueParser.parse(declaration.value)
           ├─ walk(ast) [color-mix()ノード走査]
           │      ├─ designSystem.theme.resolveValue() [変数解決]
           │      └─ WalkAction.Replace() [ノード置換]
           ├─ ValueParser.toCss(ast) [フォールバック値生成]
           └─ parent.splice() [AST挿入]
```

### データフロー図

```
[入力]                    [処理]                              [出力]

ASTノード配列 ───────▶ transform() ─────▶ colorMixDeclarations
                        (宣言収集)              (Map<AstNode[], Set<Declaration>>)
                                                    │
                                                    ▼
                                           フォールバック生成処理
                                                    │
                        ┌───────────────────────────┤
                        ▼                           ▼
                  ValueParser.parse()      designSystem.theme.resolveValue()
                  (CSS値の解析)              (変数の解決)
                        │                           │
                        ▼                           ▼
                  色空間変換/                  インライン化された値
                  ノード置換
                        │
                        ▼
                  ValueParser.toCss() ──▶ フォールバック宣言
                                          + @supports { 元の宣言 }
                                                    │
                                                    ▼
                                           変換後ASTノード配列
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| index.ts | `packages/tailwindcss/src/index.ts` | ソース | Polyfills列挙型の定義、CompileOptionsのpolyfillsオプション |
| ast.ts | `packages/tailwindcss/src/ast.ts` | ソース | optimizeAst関数内のcolor-mix()フォールバック生成処理の本体 |
| value-parser.ts | `packages/tailwindcss/src/value-parser.ts` | ソース | CSS値の解析・再構成（parse/toCss） |
| theme.ts | `packages/tailwindcss/src/theme.ts` | ソース | テーマ変数の解決（resolveValue） |
| design-system.ts | `packages/tailwindcss/src/design-system.ts` | ソース | DesignSystemインターフェース（themeプロパティ） |
| walk.ts | `packages/tailwindcss/src/walk.ts` | ソース | AST走査ユーティリティ（WalkAction.Replace等） |
| default-map.ts | `packages/tailwindcss/src/utils/default-map.ts` | ソース | DefaultMapユーティリティ（colorMixDeclarationsの管理） |
| variables.ts | `packages/tailwindcss/src/utils/variables.ts` | ソース | CSS変数の抽出ユーティリティ |
