zfb
GitHub リポジトリ

検索したい単語を入力

いつでも検索バーを開ける

Tailwind からの移行

Tailwind CSS の構成要素を、zudo-wind のトークン、バリアント、手書きの CSS、明示的なソース入力に対応付けます。

クラス互換性一覧で上流の実装済み・未実装の登録を検索できます。必要な設定、構文上の制限、ソース根拠、別個のブラウザー検証状態を示します。ソース上の対応は公開版での対応を証明しません。

互換性の結果を読む

  • 既定値がない場合: bg-gray-500 という綴りを残すなら、プロジェクトが gray-500 という色を定義します。Wind はパレットを暗黙に提供しません。

  • 設定が必要な場合: sm:block には sm ブレークポイントの設定が必要です。p-4 のようなゼロ以外の数値余白には明示的な spacingUnit が必要です。

  • ネイティブユーティリティがない場合: ring-2 や line-clamp-2 の基部は Wind カタログにありません。必要な宣言を手書き CSS に記述し、必要に応じて完全なクラス名を予約します。

  • 意図して除外した構文: 任意プロパティと !important を含むクラス表記には診断が出ます。宣言は手書き CSS に記述します。

block、hidden、inline-flex、mx-auto など構造を決めるクラスにトークンは不要です。display: none にするクラスは hidden であり、単独の none ではありません。余白、色、名前付きの書体値はプロジェクトが定義します。クラス一覧はソースで確認した対応と相違を示します。検証済みの対応として扱う前に検証状態の列を確認してください。

デフォルトテーマ変数

Tailwind のデフォルトテーマの名前空間には、--color-*、--font-*(--font-sans、--font-mono、--font-serif を含む)、--font-weight-*、--text-*、--tracking-*、--leading-*、--breakpoint-*、--container-*、--spacing と --spacing-*、--radius-*、--shadow-*、--inset-shadow-*、--drop-shadow-*、--blur-*、--perspective-*、--aspect-*、--ease-*、--animate-* が含まれます。Tailwind の import を削除すると、これらの変数の定義もなくなります。zudo-wind は暗黙には提供しません。変数がなくても zudo-wind のビルドエラーにはなりません。

手書き CSS の var() 参照を残すには、次のいずれかを行います。

  • 手書き CSS でカスタムプロパティを宣言します。

  • 設定済みのトークンの値なら、出力される --zw-<category>-<key> 変数を参照します。正確な名前はトークンのカテゴリと接頭辞の表を参照してください。

  • var(--x, <literal>) のようにフォールバックを追加します。

手書き CSS が以前 var(--color-neutral-900) を参照していた場合、neutral-900 を色トークンとして設定しているなら、出力されるトークン変数 var(--zw-color-neutral-900) に更新します。zfb wind audit は、Tailwind のデフォルトテーマ変数をフォールバックなしで参照し、走査したスタイルシートのどこにも宣言がない場合、ZW016 を監査専用情報として報告します。wind.strict: true では警告になります。この検査はヒューリスティックで、対象はエントリースタイルシートと発見された import 先だけです。CSS Modules、リンクされたスタイルシート、インラインスタイル、解決できなかった import は対象外です。wind: false の場合、ZW016 は報告されません。走査対象のどこかにその変数の宣言があれば、指摘は抑止されます。

短い手順で移行する

このガイドを載せるドキュメントサイトは、独自の chrome に引き続き Tailwind を使います。この手順とコンパイル済みサンプルが説明するのは、利用者のプロジェクトで使う zudo-wind v1 です。

  1. エントリーのスタイルシートと import 先から Tailwind の import とエンジンディレクティブを削除します。通常の手書き CSS と @layer は残します。影響を受けるデフォルトテーマ変数の参照を次のコマンドで探します。

    grep -rnoE 'var\(--(color|font|text|tracking|leading|breakpoint|container|spacing|radius|shadow|inset-shadow|drop-shadow|blur|perspective|aspect|ease|animate)[-)]' src pages
  2. エンジンの値をトップレベルの wind キーに移します。spec を設定し、リセットを選び、候補が使うトークンとブレークポイントを設定します。

  3. 有限の候補はソースに残します。ソースにないアプリ候補は safelist に、パッケージ候補はバージョン付きマニフェストに置きます。

  4. build プランを監査します。対応候補を直し、手書き名を完全一致で予約し、strict モードの前に外部ユーティリティを置き換えるか実装します。

import { defineConfig } from "zfb/config";

export default defineConfig({
  wind: {
    spec: 1,
    reset: "owned-v1",
    strict: false,
    tokens: {
      spacingUnit: "0.25rem",
      colors: { panel: "var(--app-panel)" }
    },
    breakpoints: { sm: { minWidthPx: 640 } }
  }
});

参照するカスタムプロパティは手書き CSS で宣言します。続けて完全な候補を監査、説明します。

zfb wind audit --plan build
zfb wind explain --config zfb.config.ts bg-panel
zfb wind audit --plan build --fail-on warning

プレビューではコンパイル済み zudo-wind ルールがトークンと数値余白を使います。

テーマ値を wind.tokens に移す
HTML
<article class="wind-demo-card bg-panel p-4"><h2>Workspace panel</h2><p>Token-backed color and numeric spacing.</p></article>
CSS
@layer zw-reset, zw-tokens, zfb-hi, base, components;
@layer zw-reset {
  *,
  *::before,
  *::after {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
    border-width: 0;
    border-style: solid;
    border-color: currentColor;
  }
  html {
    line-height: 1.5;
    font-family: ui-sans-serif, system-ui, sans-serif;
    -webkit-text-size-adjust: 100%;
    tab-size: 4;
  }
  body {
    line-height: inherit;
  }
  h1,
  h2,
  h3,
  h4,
  h5,
  h6 {
    font-size: inherit;
    font-weight: inherit;
  }
  a {
    color: inherit;
    text-decoration: inherit;
  }
  b,
  strong {
    font-weight: bolder;
  }
  code,
  kbd,
  samp,
  pre {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 1em;
  }
  ol,
  ul,
  menu {
    list-style: none;
  }
  button,
  input,
  optgroup,
  select,
  textarea {
    font: inherit;
    letter-spacing: inherit;
    color: inherit;
  }
  button,
  input:where([type="button"], [type="reset"], [type="submit"]) {
    background-color: transparent;
    background-image: none;
  }
  textarea {
    resize: vertical;
  }
  img,
  svg,
  video,
  canvas,
  audio,
  iframe,
  embed,
  object {
    display: block;
    vertical-align: middle;
  }
  img,
  video {
    max-width: 100%;
    height: auto;
  }
  table {
    border-collapse: collapse;
    border-color: inherit;
    text-indent: 0;
  }
  summary {
    display: list-item;
  }
  hr {
    height: 0;
    border-top-width: 1px;
  }
}
@layer zw-tokens {
  :root {
    --zw-color-panel: #eaf2ff;
    --zw-spacing-unit: .25rem;
  }
}
.wind-demo-card {
  max-width: 24rem;
  border: 1px solid #b6c4d2;
  border-radius: .5rem;
  color: #172b4d;
}

.wind-demo-card h2 {
  margin: 0 0 .5rem;
  font-size: 1.1rem;
}

.wind-demo-card p {
  margin: 0;
}
.p-4 {
  padding-top: 1rem;
  padding-right: 1rem;
  padding-bottom: 1rem;
  padding-left: 1rem;
}
.bg-panel {
  background-color: var(--zw-color-panel);
}
この例の設定
{
  "wind": {
    "spec": 1,
    "reset": "owned-v1",
    "strict": true,
    "tokens": {
      "spacingUnit": "0.25rem",
      "colors": {
        "panel": "#eaf2ff"
      }
    },
    "breakpoints": {},
    "defaultTransitionTimingFunction": "ease",
    "authoredClasses": {
      "wind-demo-card": true
    },
    "safelist": {
      "docs-preview": [
        "bg-panel",
        "p-4"
      ]
    }
  }
}
表示用の補助 CSS
.wind-demo-card { max-width: 24rem; border: 1px solid #b6c4d2; border-radius: 0.5rem; color: #172b4d; }
.wind-demo-card h2 { margin: 0 0 0.5rem; font-size: 1.1rem; }
.wind-demo-card p { margin: 0; }

Tailwind ディレクティブが残っていると、wind が false でも ZW009 で失敗します。この型付きフィクスチャは拒否されるエントリースタイルシートを示します。

@tailwind utilities;
<p>Legacy entry check</p>

期待される診断: ZW009 (error)

この例の設定
{
  "wind": {
    "spec": 1,
    "reset": "none",
    "strict": true,
    "tokens": {
      "spacingUnit": "0.25rem"
    },
    "breakpoints": {},
    "defaultTransitionTimingFunction": "ease",
    "authoredClasses": {},
    "safelist": {
      "docs-preview": []
    }
  }
}
表示用の補助 CSS

Tailwind の import も同じスタイルシート検査で ZW009 になります。

@import "tailwindcss/utilities";
<p>Legacy entry check</p>

期待される診断: ZW009 (error)

この例の設定
{
  "wind": {
    "spec": 1,
    "reset": "none",
    "strict": true,
    "tokens": {
      "spacingUnit": "0.25rem"
    },
    "breakpoints": {},
    "defaultTransitionTimingFunction": "ease",
    "authoredClasses": {},
    "safelist": {
      "docs-preview": []
    }
  }
}
表示用の補助 CSS

旧来の line-clamp-2 クラスは未対応で、ZW014 になります。失われるスタイルを調べる間は警告のままにするか、strict モードでクラス位置のエラーにします。

<p class="line-clamp-2">Two-line label</p>

期待される診断: ZW014 (warning)

この例の設定
{
  "wind": {
    "spec": 1,
    "reset": "none",
    "strict": false,
    "tokens": {
      "spacingUnit": "0.25rem"
    },
    "breakpoints": {},
    "defaultTransitionTimingFunction": "ease",
    "authoredClasses": {},
    "safelist": {}
  }
}
表示用の補助 CSS

移行できないセレクタや宣言は手書き CSS または CSS Module に記述します。以下の詳細にはリセットの正確な差、詳細度、配置の同点、未対応構文の代替策を残します。

技術リファレンス

主な変更点

  • zudo-wind はバージョン管理されたユーティリティ言語です。v1 は spec: 1 で識別され、見慣れた表記でも別のエンジンとの互換性は保証しません。

  • ユーティリティプラグインはありません。受け入れるカタログは言語バージョンごとに固定されます。

  • 設定は zfb.config.ts または zfb.config.json のトップレベルの wind キーに置くデータです。CSS ディレクティブではエンジンを設定しません。

  • パレット、余白単位、名前付きスケール、ブレークポイント、フォント、角丸、シャドウ、名前付きイージングトークンは暗黙に供給されません。トランジション系ユーティリティのデフォルトは ease です。別のプロジェクト共通設定には wind.defaultTransitionTimingFunction を指定します。

  • ソースのスキャナーには完全なクラス候補が必要です。接頭辞と実行時の値を結合してもユーティリティにはなりません。

  • どのユーティリティ基部にも一致しないプロジェクトのクラスは通常のクラステキストとして残ります。カタログの基部で始まる名前は最長一致する基部で解決され、ユーティリティとして検証されるため、トークンが足りなければ診断されます。手書き CSS 側で基部名と重なるクラスを所有する場合は、完全な候補を wind.authoredClasses に登録します。

  • カタログ外の宣言とセレクタは、手書きの CSS または CSS Modules に置きます。

ディレクティブ

wind の設定と候補の発見は CSS の外で行います。スタイルシートの移行時には Tailwind 専用のディレクティブを削除してください。入口または import 先のスタイルシートに残っていると、wind: false で生成を無効にしていても、zfb は表記とソース位置を示す ZW009 を報告し、処理に失敗します。

Tailwind の構成要素zudo-wind での扱い
@import "tailwindcss"削除します。wind は独自のレイヤー前置きを用意し、選択したリセット、設定済みトークン、解決されたユーティリティを出力します。残った import は ZW009 です。
@import "tailwindcss/preflight"削除し、wind.reset を明示的に選びます。リセットの選択肢は後述します。残った import は ZW009 です。
@import "tailwindcss/utilities"削除します。ユーティリティは完全な候補と有限のカタログから生成されます。残った import は ZW009 です。
@tailwind base、@tailwind components、@tailwind utilitiesCSS を展開するディレクティブはありません。リセットを選び、コンポーネントルールは手書きの CSS に、カタログのユーティリティは完全な候補で記述します。残ったディレクティブは ZW009 です。
@theme検証される値を wind.tokens に置きます。CSS 専用のプロパティは手書きの CSS の通常のカスタムプロパティとして残し、必要なユーティリティのトークンから参照します。
var(--<デフォルトテーマ変数>)(手書き CSS 内)Tailwind のデフォルトテーマ変数は zudo-wind からは提供されません。名前空間には --color-*、--font-*(--font-sans、--font-mono、--font-serif を含む)、--font-weight-*、--text-*、--tracking-*、--leading-*、--breakpoint-*、--container-*、--spacing と --spacing-*、--radius-*、--shadow-*、--inset-shadow-*、--drop-shadow-*、--blur-*、--perspective-*、--aspect-*、--ease-*、--animate-* が含まれます。プロパティを宣言するか、設定済みトークンの出力変数(カテゴリと接頭辞の表を参照)を使うか、var() にフォールバックを指定します。デフォルトテーマ変数も参照してください。
@sourceCSS では走査ルートを選べません。走査するファイルとパッケージルートは zfb のソースプランが管理します。ソースと候補を参照してください。
@source inline(...)アプリ所有の候補には所有者キー付きの wind.safelist 配列を使います。パッケージ所有の候補は、完全な v1 ユーティリティまたはマーカーに絞った、明示的なバージョン付き wind.manifests ファイルに入れます。各項目は厳格に検査され、無効または未知なら失敗します。パターン、波括弧展開、実行時補間の構文はありません。
@source not(...)CSS の否定ディレクティブはありません。ソースプランのルートと除外規則を使います。ソースと候補を参照してください。
@custom-variant設定可能な組み込みバリアントは dark だけです。属性と値を wind.dark に設定し、ほかのセレクタ条件は手書きの CSS に記述します。
@applyユーティリティ名を宣言に展開するディレクティブはありません。必要なセレクタに宣言を手書きします。
@utilityカスタムユーティリティで言語を拡張することはできません。手書きの CSS にクラスを定義し、その完全な候補がマークアップにある場合は同じ表記を wind.authoredClasses に予約します。
@variantスタイルシート内でバリアントを展開するディレクティブはありません。対応する完全な候補をマークアップで使うか、セレクタと条件を手書きの CSS に記述します。
@pluginプラグインは読み込みません。組み込みカタログか手書きの CSS を使います。
@config設定データはプロジェクトの wind キーに移します。CSS はユーティリティ設定ファイルを読み込みません。
@referenceスタイルシートを展開するためのユーティリティ参照 import はありません。CSS Modules とグローバル CSS は手書きのままにし、値は wind.tokens に設定します。

スキャナーは旧式の宣言値関数 theme()、--spacing()、--alpha()、--value() も ZW009 で拒否します。コメントと文字列の内容は無視します。通常の @layer 宣言と、レイヤーを明示する CSS import は有効です。エラーの契約は診断とツールを参照してください。

設定

旧式のトップレベルの tailwind キーは zudo-wind では意味を持ちません。残っていれば、移行方法を示す設定エラーになります。wind に置き換えてください。切り替え後に wind キーを省略すると、空の v1 設定が有効になります。つまり生成は有効、リセットは none、トークンマップは空です。

import { defineConfig } from "zfb/config";

export default defineConfig({
  wind: {
    spec: 1,
    reset: "owned-v1",
    defaultTransitionTimingFunction: "cubic-bezier(0.4, 0, 0.2, 1)",
    tokens: {
      spacingUnit: "0.25rem",
      colors: { panel: "var(--app-panel)" }
    },
    breakpoints: {
      sm: { minWidthPx: 640 }
    },
    dark: { attribute: "data-theme", value: "dark" }
  }
});

以前の無効化設定 tailwind: { enabled: false } は wind: false になります。これにより wind の生成、トークン検証、マニフェスト読み込み、候補走査を無効にします。手書きのグローバル CSS、CSS Modules、構文ハイライトは続き、残存ディレクティブの検査も続きます。フィールドとマージ規則は設定を参照してください。

テーマとトークン

v1 は色パレットや余白スケールを同梱しません。名前付きのサイズ、フォントファミリーやウェイト、文字サイズ、行の高さ、字間、角丸、シャドウ、z-index、イージング、ブレークポイントもありません。定数 0、px、カタログのキーワードはテーマを意味しません。

Tailwind の --text-<n> と --text-<n>--line-height は、同じキーと size、任意の lineHeight を持つ fontSizes 項目に対応します。

Tailwind の変数の組zudo-wind のトークン
--text-<n> + --text-<n>--line-heightfontSizes: { <n>: { size, lineHeight } }

ユーティリティが必要とする値を wind.tokens に移します。p-4 のような数値の余白は設定された spacingUnit を倍にし、名前付きの値は対応する群のマップから取得します。たとえば次の設定は、2 つの色ユーティリティをプロジェクト所有のプロパティに結び付けます。

{
  "wind": {
    "tokens": {
      "spacingUnit": "0.25rem",
      "colors": {
        "panel": "var(--app-panel)"
      }
    }
  }
}
:root {
  --app-panel: #f4f1ec;
}

これで bg-panel と text-panel は colors.panel から解決されます。トークンの項目は検証されるデータであり、実行可能な CSS や JavaScript ではありません。参照されるカスタムプロパティは手書きの CSS に残り、生成されたトークン変数がそれを指します。トークンや数値の余白単位がない場合、厳格な候補の発生元で報告され、デフォルトで補われません。マップと値の規則はトークンを参照してください。

手書き CSS に Tailwind のデフォルトテーマ変数への参照が残っている場合は、デフォルトテーマ変数に挙げた方法のいずれかで対応してください。

大文字の DEFAULT は無効です。小文字の default は、その意味が定義されたマップだけで使います。radii.default は rounded、shadows.default は shadow の値を与えます。色や余白のフォールバックにはなりません。

リセット

デフォルトの reset は none で、リセット宣言は出力されません。ブラウザのデフォルトに対してページが置く前提に応じて選んでください。

リセット主な動作
noneリセットのバイト列はありません。手書きの CSS で変えない限り、リスト、見出しのサイズ、ボーダーの初期値、フォーム部品はブラウザ標準のスタイルを保ちます。
minimal-v1border-box に設定し、body の margin を削除し、フォーム部品にフォントを継承させます。リストマーカーの削除や見出しサイズの正規化はしません。
owned-v1border-box に設定し、margin、padding、ボーダーの初期幅を消去してボーダーを実線にします。リストマーカーを削除し、見出しにサイズとウェイトを継承させ、フォーム部品のフォントとボタン背景を正規化します。

owned-v1 では、デザインに必要なリストマーカーを戻してください。スキャフォールドの .prose ルールは disc と decimal のリストを明示的に復元します。見出しはブラウザ標準のサイズを保持しないため、手書きの CSS または設定済みの文字サイズユーティリティで指定します。接尾辞のない border ユーティリティは、どのリセットでも自身で実線のボーダーを設定します。フォーム部品はフォントスタイルを継承し、リセットはブラウザ標準のフォーカスアウトラインと appearance を維持します。wind のユーティリティはレイヤーを持たず、既定では手書きのグローバル CSS の後に続きます。名前付きレイヤーの通常の宣言より優先されますが、レイヤーのない手書きのルールは詳細度や後続順によって優先されます。逆の順序はユーティリティの配置と同点を参照してください。リセットは明示的な zudo-wind の選択であり、別の preflight とバイト単位で一致する保証ではありません。宣言とレイヤー順はカスケードとリセットを参照してください。

Tailwind preflight との違い

比較の基準は Tailwind CSS 4.2.0 の preflight と owned-v1 です。先行するレシピ移行では Chromium 147・151 と WebKit 26.4 で測定しました。追加の #3451 フィクスチャは Chromium 151 と WebKit 26.5 で、375px と 1280px の幅を使って確認しました。いずれも網羅的なマトリクスではありません。測定したプロジェクトでは、Tailwind のテーマは --default-font-family を --font-sans から、--default-mono-font-family を --font-mono から解決します。

セレクタTailwind 4.2.0 preflightowned-v1 と影響
html のフォントテーマの --default-font-family / --font-sans固定の ui-sans-serif, system-ui, sans-serif。子孫が継承するフォントが変わることがあります。
html のタップ時の色-webkit-tap-highlight-color: transparentルールなし。ブラウザーのタップ時の色がすべての要素に継承されます。
code, kbd, samp, pre のフォントテーマの --default-mono-font-family / --font-mono固定の ui-monospace, SFMono-Regular, Menlo, monospace。両方が Menlo に解決される macOS ではスクリーンショットで差が見えないことがあります。
smallfont-size: 80%ルールなし。ブラウザー標準のサイズになります。
sub, supfont-size: 75%; line-height: 0; position: relative; vertical-align: baseline、さらに sub { bottom: -0.25em } と sup { top: -0.5em }ルールなし。行ボックスが広がり、レイアウトがずれることがあります。
hrcolor: inherit色のルールなし。ブラウザー標準色が境界線に影響することがあります。
button と button/reset/submit 型の inputappearance: buttonappearance のルールなし。ネイティブの表示が異なることがあります。
button, input, select, optgroup, textareaborder-radius: 0; background-color: transparent; opacity: 1owned-v1 は button と button 型 input の背景を透明にしますが、Chromium で測定した text input はブラウザー標準の白い背景を保ちます。この宣言を揃えるには、下記の共通フォーム部品ルールを追加します。
::placeholderopacity: 1 と、対応ブラウザーでは color: color-mix(in oklab, currentcolor 50%, transparent)ルールなし。ブラウザー標準の色と不透明度になります(測定した Chromium では灰色)。
::file-selector-button境界線と背景のない、文字のスタイルを継承する表示。右方向に 4px の余白があり、appearance: button疑似要素のルールなし。ネイティブの立体的なファイル選択ボタンが残ります。
[hidden]:where(:not([hidden="until-found"]))display: none !importantブラウザー標準の hidden ルールのみ。hidden 属性の付いた要素が display ユーティリティで意図せず表示されることがあります。

元の 差分 0 要素 という結果は、そのフィクスチャの範囲内でした。元のフィクスチャには単独の text input がなく、abbr[title]、progress、:-moz-focusring も調べていません。#3451 のフィクスチャでは、下記の共通フォーム部品ルールを追加する前に、owned-v1 の text input がブラウザー標準の白い背景を保ち、Tailwind では透明になる差が見つかりました。ルール追加後は Chromium 151 と WebKit 26.5 の両方で、両方の幅における全要素の標準 computed style と2つの疑似要素が一致しました。4組のスクリーンショットもピクセル単位で同一でした。Chromium ではリンクまで Tab キーで移動した後も、キーボードフォーカスリングが表示されました。この測定範囲はすべてのフォーム部品、フォント、プラットフォームを網羅するものではありません。要素ごとの getComputedStyle の差分には ::placeholder と ::file-selector-button は現れないため、疑似要素を明示して取得し、見た目が重要ならピクセルも比較してください。

測定された preflight の振る舞いを戻したい場合は、次の CSS を手書きのスタイルシートに追加します。プロジェクトのフォントが異なる場合、例のスタックを置き換えてください。v3 に暗黙のテーマはありません。したがって、この例のように --font-sans と --font-mono を手書き CSS で宣言するか、両方の font-family にリテラルのスタックを指定する必要があります。

@layer base {
  :root {
    --font-sans: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
    --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
  }
  html { font-family: var(--font-sans); -webkit-tap-highlight-color: transparent; }
  code, kbd, samp, pre { font-family: var(--font-mono); }
  small { font-size: 80%; }
  sub, sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; }
  sub { bottom: -0.25em; }
  sup { top: -0.5em; }
  hr { color: inherit; }
  button, input:where([type="button"], [type="reset"], [type="submit"]) { appearance: button; }
  button, input, select, optgroup, textarea {
    border-radius: 0;
    background-color: transparent;
    opacity: 1;
  }
  ::placeholder { opacity: 1; color: color-mix(in oklab, currentcolor 50%, transparent); }
  ::file-selector-button {
    box-sizing: border-box;
    margin: 0;
    margin-inline-end: 4px;
    padding: 0;
    border: 0 solid;
    border-radius: 0;
    background-color: transparent;
    font: inherit;
    font-feature-settings: inherit;
    font-variation-settings: inherit;
    letter-spacing: inherit;
    color: inherit;
    opacity: 1;
    appearance: button;
  }
  /* 任意指定。display ユーティリティがあっても hidden 要素を非表示に保つ。 */
  [hidden]:where(:not([hidden="until-found"])) { display: none !important; }
}

共通フォーム部品のルールでは、Tailwind が設定する border radius、背景色、不透明度を戻します。button のルールはファイル選択ボタンの疑似要素には適用されないため、独立したルールが必要です。Chromium 151 の画像ギャラリーのレシピでは、測定に基づくファイルボタンのルールを追加すると、テストした 2 ページの明暗両テーマでピクセルと疑似要素の差分が 0 になりました。[hidden] のルールは任意です。!important は Tailwind preflight と同様に display ユーティリティより優先させるためです。レイヤーの前置きでは zw-reset が手書きの base より前にあるため、この補完ルールでリセットを上書きできます。キーボード操作時のフォーカス表示を残し、広範なリセットを無条件に貼り付けず、採用するルールを確認してください。リセット宣言を戻しても、ユーティリティの配置や関係セレクタの詳細度は戻りません。この差分は #3386 で追跡しています。

バリアントと文法

次の表は各構成要素に対する v1 の扱いを示します。対応する連鎖はレスポンシブ、ダーク、pointer、関係、状態、疑似要素、ユーティリティの順で、カテゴリは重複できません。

構成要素仕様上の扱いと規則
max-* を含むブレークポイント変更して採用 (W02)。 各名前に正の整数の minWidthPx を設定します。sm は最小幅、max-sm はその幅より下の排他的な範囲です。幅はピクセルで、ルートのフォントサイズには追従しません。
dark変更して採用 (W09)。 属性と値を設定するまで無効です。条件は要素自身または祖先に一致し、詳細度を増やしません。
状態バリアント採用 (W03)。 hover、focus、focus-visible、active、disabled、checked、focus-within、open、first、last を使えます。すべての hover 条件には hover 対応のメディアクエリが付きます。
first と last採用 (W03)。 それぞれ :first-child と :last-child を対象にします。
名前付き形式を含む group-* と peer-*変更して採用 (W04)。 名前のない group と peer マーカーは対応する状態で使えます。group は祖先、peer は前の兄弟要素です。マーカーは単独で置き、CSS は出力しません。group/menu や group-hover/menu:block のような名前付き形式は拒否されます。
疑似要素バリアント採用 (W05)。 before、after、marker、placeholder、backdrop、selection を使えます。before と after は content 宣言を追加しないため、必要なら手書きします。
aria-* と data-[...] のバリアント診断で拒否 (W06)。 属性バリアントは ZW004 です。セレクタは手書きの CSS に置きます。
任意セレクタのバリアント診断で拒否 (W07)。 [&_a]:underline のようなセレクタは ZW004 です。手書きの CSS に記述します。
バリアントの連鎖変更して採用 (W08)。 レスポンシブ、ダーク、pointer、関係、状態、疑似要素をそれぞれ最大 1 つ、指定順に使います。各機能とトークンが設定済みなら sm:dark:hover:bg-panel は正規形です。重複や順序違いは診断されます。
色の不透明度修飾子採用 (W10)。 色の接尾辞には 0~100 の整数を指定し、設定された色を透明色と oklab で混ぜます。bg-panel/40 は有効です。余白やサイズには適用できません。
分数変更して採用 (W11)。 対象となるサイズ、移動、7つの inset 基部に加え、アスペクト比にも正の整数比を指定できます。w-1/2 は利用可能なサイズ基準の半分、aspect-4/3 は aspect-ratio: 4 / 3 です。アスペクト比の分子と分母はそれぞれ 1~1,000,000 です。小数には aspect-[1.5/2.5] のような任意値を使います。left-1/2 は left: calc(100% * 1 / 2) を出力し、負の inset 分数も使えます。サイズまたは inset のスラッシュは色の不透明度を意味しません。
トランジション現在の v1 の動作。 transition-shadow は box-shadow を設定し、transition-colors は outline-color を含みます。transition-none 以外のトランジション系ユーティリティは 150ms の時間を設定し、wind.defaultTransitionTimingFunction を使います。デフォルトは ease です。Tailwind 4 のデフォルト時間関数を保つには cubic-bezier(0.4, 0, 0.2, 1) を設定します。同じバリアント区画では明示した ease-* ユーティリティが優先されます。
任意の値変更して採用 (W12)。 対応するユーティリティの基部には、CSS プロパティの検証を通る、対応の取れた角括弧値を付けられます。空白にはアンダースコアを使い、エスケープしたものは文字どおり残ります。Tailwind は calc() の演算子の前後に自動で空白を入れていましたが、zudo-wind は入れません。w-[calc(100vw_-_2rem)] と書いてください。w-[calc(100vw-2rem)] にはエラーでその綴りを提案します。text-[color:var(--x)] のようなデータ型ヒントには対応しません。曖昧な変数には名前付きトークンを使ってください。url() と、宣言などの構文を注入する値は拒否されます。
任意のプロパティ診断で拒否 (W13)。 [overflow-wrap:anywhere] のようなトークンは ZW004 です。宣言は手書きの CSS または CSS Module に置きます。
!important の表記診断で拒否 (W14)。 先頭と末尾のどちらも ZW004 です。意図的な important 宣言は手書きの CSS に置きます。
負のユーティリティ採用 (W15)。 負の値を許可するカタログ群だけが符号を受け入れ、群で定義された方法で値に適用します。-mt-2 は有効、-p-2 は無効です。
space-* と divide-*変更して採用 (W20)。 hidden 属性で絞られた後続の表示対象の直接の子を対象にします。前者は対応する margin、後者は実線の左または上のボーダーを設定します。逆方向フラグはなく、疑似要素バリアントとも組み合わせられません。

pointer-coarse と pointer-fine は設定不要です。any-pointer-*、motion-*、print、portrait、任意の [@media(...)] は未対応です(ZW002/R04、任意セレクターは ZW004/R09)。checked:、group-checked:、peer-checked:、max-sm:peer-checked:visible は使えますが、indeterminate、required、invalid は未対応です。selection: は content を生成せずに使えます。標準的な focus-visible:outline focus-visible:outline-2 は計算上の outline 幅 2px に解決します。

装飾の厚さと style は decoration-<整数>、0 以上の decoration-[<length>]、正確な decoration-solid|double|dotted|dashed|wavy を使います。thickness/style の負数やスラッシュ、decoration-auto、decoration-from-font は未対応です。設定済みの完全な色トークンは style 名より優先です。colors: { wavy: "#123456", "dotted-muted": "#123456" } なら decoration-wavy と decoration-dotted-muted/40 は text-decoration-color を出力します。トークンがなければ decoration-wavy は text-decoration-style を出力します。solid、double、dotted、dashed は以前から色トークン名として予約されていましたが、wavy は予約されていませんでした。衝突する名前で両方必要なら .decorated { text-decoration-style: wavy; text-decoration-color: var(--zw-color-wavy); } を手書きし、audit が診断する場合は decorated を wind.authoredClasses に登録してください。

候補の文法では区切りを分割する前に角括弧、丸括弧、引用符の対応を取るため、角括弧値内のコロンやスラッシュはバリアントや修飾子の区切りにはなりません。完全なカタログはバリアント、ユーティリティの文法、ユーティリティリファレンスを参照してください。

ユーティリティの配置と同点

Tailwind v4 のエントリーは通常、自前の CSS より前にユーティリティを import します。そのため、ユーティリティと詳細度が同じ手書きのルールは、後にあることで優先されていました。zudo-wind は既定でユーティリティを手書きのグローバル CSS の後に置くため、この勝敗が逆になります。

/* 手書き */
.card {
  color: red;
}
<p class="card text-accent">Card</p>
構成順序色
Tailwind v4、ユーティリティを先に importユーティリティ、.cardred
zudo-wind の既定(after-authored).card、ユーティリティaccent
zudo-wind の before-authoredユーティリティ、.cardred

Tailwind の順序を保つには配置を設定します。

wind: {
  utilities: { placement: "before-authored" }
}

このとき出力されるスタイルシートは、レイヤーの前置き、巻き上げられた外部 import、ハイライトブロック、リセットとトークンのレイヤー、@property 登録、レイヤーのないユーティリティ、手書きのグローバル CSS、最後に CSS Modules の順になります。配置が決めるのは、レイヤーのないルール同士で詳細度が同じ場合の勝敗だけです。どちらの設定でも、詳細度の高い手書きのセレクターが優先され、レイヤー内の手書きのルールはどのユーティリティにも負け、手書きの !important 宣言が優先されます。ブレークポイントとダークのバリアントは詳細度を加えないため、同じ同点の規則に従います。ユーティリティを名前付きレイヤーに出力する機能はありません。

関係バリアントの詳細度

Tailwind は group-hover:text-accent を .group-hover\:text-accent:is(:where(.group):hover *) として出力し、詳細度は (0,2,0) です。zudo-wind は :where(.group:hover) .group-hover\:text-accent を出力し、詳細度は (0,1,0) です。peer-* のバリアントも同様です。配置はセレクターを変えないため、この詳細度は戻りません。以前は group や peer の状態に負けていた (0,2,0) や (0,1,1) の手書きのルールは、どちらの配置でも優先されるようになります。

/* (0,2,0): group-hover:text-accent に勝つようになる */
.panel .title {
  color: red;
}

ルールごとに次のいずれかを選びます。

  • 手書きのセレクターの詳細度をユーティリティと同じにします。たとえば :where(.panel) .title です。既定の配置では、状態のほうが順序で優先されます。

  • @layer components { .panel .title { color: red; } } のように手書きのルールをレイヤーに移し、すべてのユーティリティが優先されるようにします。

  • ホバー時のスタイルも手書きの CSS で指定します。.panel:hover .title { color: var(--zw-color-accent); } です。

以前は何も出力しなかったクラス

クラスに見える文字列のすべてがユーティリティルールを作るわけではありません。site-header のような名前はユーティリティ基部に一致しないため、通常のクラスとしてマークアップに残り、wind はルールを出力しません。一方 text-link は text 基部に一致してユーティリティとして検証されるため、必要なトークンがなければ ZW006 になります。未解決の名前をすべて通常のクラスとして扱うのではなく、綴り間違いを検出できる厳格な分類です。単独の group または peer マーカーもルールを出力せず、対応する候補のために関係メタデータを提供します。

line-clamp-2、order-1、basis-1/2、container など zudo-wind が実装しない Tailwind ユーティリティは、通常のテキストとして扱われません。代わりに手書きすべき宣言を添えた ZW014 として報告され、既定では警告、wind.strict: true ではエラーです。card__title のようにアンダースコアを含む名前は通常のクラスのままです。

候補の結果動作
解決されたユーティリティwind がルールを出力します。
通常のクラスまたはマーカークラス位置の名前がユーティリティ基部に一致しない場合はマークアップに残り、ユーティリティルールを出力しません。手書きの CSS ではスタイルを指定できます。
認識されたが無効なユーティリティ厳格なクラス、セーフリスト、マニフェストの発生元には診断が付きます。確信度の低いソーステキストでは監査情報です。不足トークンは自動補完されません。
構文不正、未対応、または未知の明示的なユーティリティ入力診断を出して処理が失敗します。未知の明示的なセーフリストやマニフェスト項目は失敗しますが、関連するユーティリティ基部を持たないクラス位置の名前は通常のままです。

zfb wind audit は、通常のクラス位置の名前、不足または使われていない候補、動的な断片、同じクラスリストリテラル内のプロパティ競合を列挙します。意図的な手書きクラスとスペルミスしたユーティリティの区別に役立ちますが、代替の候補は推測しません。ユーティリティ基部から始まる手書きクラスは、{ "text-link": true } のように wind.authoredClasses に完全な候補表記を追加して予約します。hover:text-link のような候補ではバリアント連鎖も含めます。一致すると、その候補はすべての発生元でユーティリティの検証、診断、CSS 生成を抑止します。それ以外の場合はユーティリティの綴りを直すか、不足トークンを宣言します。診断とツールを参照してください。

ZW014 移行語彙 v4 は論理方向の ms-*/me-*、ps-*/pe-*、start-*/end-*、border-s/border-e を報告します。margin-inline-*、padding-inline-*、inset-inline-*、border-inline-* の CSS を自作してください。isolation、float、clear、word-break/break-*、transform origin、filter、backdrop-filter、text-shadow、グラデーションも対象です。完全なクラス名を wind.authoredClasses に予約し、CSS を自作してください。合成 CSS は生成されません。origin-story、float-label、clear-fix は自作クラスとして残り、実際に解決するカタログ/トークンユーティリティが優先です。グラデーションには bg-gradient-to-*、bg-linear-to-*、整数角度の bg-linear-*、bg-radial と角括弧付き値、bg-conic と整数角度、宣言済み色・current・transparent・角括弧付き色/位置の from-*/via-*/to-* を含みます。background-image を自作します。角括弧なしの stop percentage(from-10%、via-30%、to-90%)は parser が拒否し、from-[60%] は ZW014 に到達します。

移行例

basic-blog スキャフォールドの callout は my-6、rounded-md、border-l-4、px-4、py-3、dark:bg-sky-950/40、group-hover:text-accent などの実際の候補を使います。移行表では表記を維持します。採用されるとは、スキャフォールドがトークンとバリアントを明示的に設定した後に解決されるという意味です。

古いスタイルシートは Tailwind の import と独自のダークバリアントから始まり、@theme で 3 つのプロジェクト色を宣言します。

@import "tailwindcss";
@custom-variant dark (&:where([data-theme="dark"], [data-theme="dark"] *));

@theme {
  --color-accent: oklch(0.53 0.21 258);
  --color-code-bg: #2b303b;
  --color-code-fg: #c0c5ce;
}

callout のソースには、次の tone 文字列があります。

tone: "border-sky-500 bg-sky-50 dark:bg-sky-950/40",
accent: "text-sky-700 dark:text-sky-300",

2 つの Tailwind ディレクティブを削除します。ユーティリティの値を設定に移し、CSS 専用のテーマプロパティは手書きのままにします。

import { defineConfig } from "zfb/config";

export default defineConfig({
  wind: {
    spec: 1,
    reset: "owned-v1",
    tokens: {
      spacingUnit: "0.25rem",
      colors: {
        accent: "var(--color-accent)",
        "sky-50": "#f0f9ff",
        "sky-300": "#7dd3fc",
        "sky-500": "#0ea5e9",
        "sky-700": "#0369a1",
        "sky-950": "#082f49"
      },
      radii: { md: "0.375rem" }
    },
    breakpoints: { sm: { minWidthPx: 640 } },
    dark: { attribute: "data-theme", value: "dark" },
    authoredClasses: { prose: true }
  }
});

この設定抜粋は、示した callout のトークンをカバーします。完全なスキャフォールド設定では、残りの候補と手書きの CSS が使うすべての色とスケールも宣言します。暗黙に補完されるマップはありません。

テーマプロパティを既存の手書きの base レイヤーに統合し、color-scheme と selection のルールを保ちます。

@layer base {
  :root {
    --color-accent: oklch(0.53 0.21 258);
    --color-code-bg: #2b303b;
    --color-code-fg: #c0c5ce;
    color-scheme: light;
  }

  [data-theme="dark"] {
    --color-accent: oklch(0.79 0.13 254);
    color-scheme: dark;
  }
}

既存の base と components レイヤーは残します。wind の前置きが順序を定めます。手書きの .prose クラスはスタイルシートに残し、authoredClasses に完全な名前を登録します。デフォルトテーマ変数で説明したように、色トークンが設定されているなら、手書き CSS 内の旧 var(--color-neutral-900) 参照を出力されるトークン変数 var(--zw-color-neutral-900) に更新します。設定済みの accent トークンは手書きの --color-accent を参照するため、テーマ切り替えでは引き続きその値を変更できます。スキャフォールドは owned-v1 リセットを使いますが、ほかのプロジェクトのデフォルトは none です。ここで扱うのは言語とスタイルシートの変更です。プロジェクト全体の移行順序はv3 への移行を参照してください。

未対応の機能と代替方法

  • 暗黙のパレットや余白スケールはありません。プロジェクトの値を wind.tokens に宣言します。

  • shadow に色を合成する機能はありません。shadow-<color> と有効な shadow-<color>/<opacity>(/0~/100)は colors トークンを shadow に適用しません。色を shadows トークンに含めるか、完全な box-shadow を CSS に記述してクラスを予約してください。同名の colors と shadows トークンがある場合、slash のない shadow-<name> は shadow トークンとして解決しますが、slash 修飾子は未対応です。shadow-none と shadow-[0_1px_2px_#000] のような完全な任意値は使えます。

  • ring、animation、scale、transform 文字列、任意プロパティのユーティリティはありません。手書きの CSS または CSS Module に宣言します。

  • 属性や任意セレクタのバリアント、名前付き group や peer はありません。手書きのセレクタを使います。

  • プラグイン定義のクラスや @apply 展開はありません。対応するユーティリティにはカタログの候補を使い、独自の宣言は CSS に残します。

  • 実行時に組み立てる候補や正規表現のセーフリストはありません。有限のリテラルマップ、所有者キー付きセーフリスト、厳格なバージョン付きパッケージマニフェストを使います。

v1 カタログはユーティリティリファレンス、候補と移行エラーの調査は診断とツールを参照してください。

Revision History

作成更新