
# 兼容性与升级

本页汇总升级前或依赖精确输出时需要了解的信息：运行环境要求、该移植版本跟随哪个 TailwindCSS 版本、TailwindPHP 与 TailwindCSS 有哪些已知差异，以及各版本的说明。完整历史记录请见 [CHANGELOG.md](https://github.com/inline0/tailwindphp/blob/main/CHANGELOG.md)。

## 要求

- **PHP 8.2 或更高版本。** 测试套件在 PHP 8.2、8.3 和 8.4 上运行。
- **`ctype` 和 `mbstring` 扩展。** 编译器会调用 `ctype_*` 和 `mb_chr()`。大多数 PHP 构建以及官方 Docker 镜像都附带这两个扩展，但 `composer.json` 尚未声明它们（[#11](https://github.com/inline0/tailwindphp/issues/11)），因此缺少这些扩展的构建虽然能安装软件包，却会在运行时失败。
- **可选：`pcntl`** 让 CLI 的 `--watch` 模式能在 `SIGINT`/`SIGTERM` 上正常停止。没有它，监视模式仍可使用。

不涉及 Node.js、FFI 或原生二进制文件。

## 跟踪的 TailwindCSS 版本

版本 1.7.0 跟踪 **TailwindCSS v4.3.3**。上游仓库固定为 `reference/tailwindcss` 中的 git 子模块，测试套件从该固定检出版本中提取，且每次推送都会运行 4,427 测试（请参阅[性能与测试](https://tailwindphp.inline0.dev/zh/docs/advanced/performance)）。移植的插件遵循 `@tailwindcss/typography` 和 `@tailwindcss/forms`，类实用工具遵循 clsx、tailwind-merge 和 CVA；这些依赖也都以同样方式固定。

## 与 TailwindCSS 的已知差异

### 序列化细节

生成的 CSS 与参考测试套件一致。序列化的少数细节与 TailwindCSS CLI 的输出不同，但都不会影响层叠效果：

- 厂商前缀：参考实现同时输出作者编写的 `-webkit-*` 行和生成的行时，TailwindPHP 只输出一行。
- 降级处理后的伪元素（`::file-selector-button`、`::-webkit-datetime-edit-*`）仍保留在作者编写的选择器列表中，不会拆分为每个伪元素各一条规则。
- 作者编写的单引号字符串仍保留单引号（`'Segoe UI'`），不会被规范化为双引号。
- 同时出现的长属性不会组合成简写属性（Tailwind 自身的输出无需这样处理）。
- `.p-0` 会保留 `padding: 0px`；参考实现 CLI 输出 `padding: 0`，因为提取出的测试语料固定使用 `0px` 形式。压缩器会将其缩短为 `0`。

### 未包含的内容

TailwindPHP 是一个 CSS 编译器。它不包含 Tailwind 生态系统中的编辑器工具（IntelliSense、自动补全、类名排序）和源码映射，因此 CLI 没有 `--map` 选项。

### 内容扫描

`tw::generate()` 和 `TailwindCompiler::generate()` 只从 `class` 和 `className` 属性读取类名。若类名位于 PHP 或 JavaScript 字符串中，请使用 [`tw::extractCandidatesFromStrings()`](https://tailwindphp.inline0.dev/zh/docs/api#twextractcandidatesfromstrings) 或 `@source inline("…")`。`@source` 的路径形式会被 API 忽略，且只被 CLI 部分支持（见下文）。

### 当前版本的已知问题

| 领域 | 当前行为 | 问题 |
|---|---|---|
| CLI `@source` | 不会应用路径和 glob 模式；系统会扫描输入文件所在的目录，并且 `@source not` 不会排除任何内容。请参阅[CLI 扫描的内容](https://tailwindphp.inline0.dev/zh/docs/cli#what-the-cli-scans) | [#8](https://github.com/inline0/tailwindphp/issues/8) |
| CLI `--optimize` | 和 `--minify` 一样会进行压缩 | [#9](https://github.com/inline0/tailwindphp/issues/9) |
| CLI 长选项 | `--input file.css`（以空格分隔）会被忽略；请使用 `--input=file.css` 或 `-i file.css` | [#13](https://github.com/inline0/tailwindphp/issues/13) |
| 插件变体 | `addVariant()`/`matchVariant()` 变体和排版元素修饰符（`prose-headings:` …）编译时不会包含其选择器 | [#10](https://github.com/inline0/tailwindphp/issues/10) |
| `@apply` 混入 | `@apply --my-mixin;` 会被丢弃，而非直接传递 | [#12](https://github.com/inline0/tailwindphp/issues/12) |
| 参考实现中的导入 | 如果实用工具导入之前有参考导入，输出将为空；`@import "tailwindcss" reference` 不起作用 | [#14](https://github.com/inline0/tailwindphp/issues/14) |

## 升级说明

### 1.7.0

- **输出会逐字节变化**，与 1.6.x 相比如此，但功能上仍与 TailwindCSS v4.3.3 参考实现等效。可见变化包括：
  - 间距乘数：`p-1` 会输出 `padding: var(--spacing)`，而不是 `calc()`；乘数为 `0` 时会输出纯零长度值。
  - 分数会折算为百分比：`w-1/2` 会输出 `width: 50%`。
  - 颜色：`oklch()`/`oklab()` 的亮度会序列化为百分比（`oklch(62.3% .214 259.815)`），`white` 和 `black` 会缩短为 `#fff` 和 `#000`。
  - CSS2 伪元素会序列化为单冒号形式（`:before`、`:after`、`:first-letter`、`:first-line`）。
  - 嵌套的 `@media`/`@supports`/`@container` 规则会按源代码顺序在原处展开，而不是提升到末尾；声明会按照 lightningcss 的顺序重新排列；被覆盖的重复声明会被移除。
- **以输出为键的缓存**会失效一次。`tw::generate()` 的文件缓存不会将 TailwindPHP 版本纳入键中，因此升级后请运行 `tw::clearCache()`（或你传入的目录 `cache`）。[编译器状态缓存](https://tailwindphp.inline0.dev/zh/docs/advanced/caching#compiler-state-cache)会自动失效。
- **新增：** 作者 CSS 中的 `@variant`、`@apply` 中的 CSS 混入、`@media reference` 和 `@import "…" reference`、用于函数式 `@utility` 的完整 `--value()`/`--modifier()` 引擎、更严格的 `@utility` 名称验证，以及 `tw::compile()` 的 `polyfills` 选项。

### 1.6.1

- **新增：**`container` 工具（`width: 100%` 加上每个断点一个 `max-width`）。
- 组合后的 `--tw-*` 变量（平移、缩放、旋转、倾斜、滤镜等）现在会注册到 `@property`，因此样式表会获得这些 `@property` 规则，且 `translate-x-7` 等变换会在浏览器中生效。

### 1.6.0

- **新增：** 持久化编译器状态缓存（在 `tw::compile()` 和 `TailwindCompiler` 上使用 `stateCacheFile`，`StateCache\compileCssCached()`），以及拆分后的 `parseCssState()`/`finalizeCssState()`/`compileParsed()` 函数。现有调用的行为完全不变。

### 1.5.0

- 覆盖 `generate()` 或 `css()` 的 `TailwindCompiler` 子类必须添加可选的 `bool $minify = false` 参数；PHP 会拒绝省略父类可选参数的覆盖实现。
- 压缩后的输出来自序列化器，因此压缩字节与 1.4.x 略有不同（以压缩输出为键的缓存会失效一次）。
- **新增：**`generateExact()` 和 `cssExact()`，用于由一个长期运行的编译器生成每页 CSS。
