canonicalizationで高精度数値の折り畳みを防止
Tailwind CSS の canonicalization が、calc 除算で生成される高精度パーセンテージを自動折り畳みしないように変更され、提案結果がユーザーフレンドリーになりました。
背景
Tailwind CSS はクラス名の canonicalization 時に calc 式の除算結果を数値化し、w-[calc(100%/3.5)] を w-[28.571428571428573%] のように展開していました。計算結果は数値的に正しいものの、小数点以下が多数桁にわたることで IDE の IntelliSense 提案が読みにくくなるという実務上の課題がありました。この問題は tailwindlabs/tailwindcss-intellisense#1591 で報告されています。
このため、ユーザーが期待する「元の calc 式をそのまま提示する」振る舞いへの変更が求められました。
技術的な変更
packages/tailwindcss/src/constant-fold-declaration.ts の constantFoldDeclaration 関数に、高精度判定ロジックが追加されました。除算処理で一度 computed = lhs[0] / rhs[0] を算出し、Math.round(computed * 100) / 100 !== computed が true であれば折り畳みを中断します。これにより小数点以下が .xx を超える結果は保持されます。
変更前:
if (lhs[1] === null && rhs[1] === null) {
folded = true
return WalkAction.ReplaceSkip(ValueParser.word(`${lhs[0] / rhs[0]}${lhs[1] ?? ''}`))
}
変更後:
if (lhs[1] === null && rhs[1] === null) {
let computed = lhs[0] / rhs[0]
// Only fold with .xx precision, anything beyond that might be a bit too much.
if (Math.round(computed * 100) / 100 !== computed) {
break
}
folded = true
return WalkAction.ReplaceSkip(ValueParser.word(`${computed}${lhs[1] ?? ''}`))
}
テストも同時に拡充され、packages/tailwindcss/src/constant-fold-declaration.test.ts に高精度結果が折り畳まれないことを確認するケースが追加されました。また canonicalize-candidates.test.ts へ w-[calc(100%/3.5)] がそのまま保持される回帰テストが導入されています。
設計判断
この変更は 「小数点以下 2 桁までの精度でのみ定数畳み込みを許容」 という明確な閾値を設ける設計判断に基づきます。既存ロジックに最小限の分岐を加えることで後方互換性を保ちつつ、数値の可読性を優先する方針が反映されています。計算結果の正確性は変わらず保持され、ユーザー体験の向上が得られます。
まとめ
canonicalization が高精度数値を折り畳まないようになったことで、calc 式をそのまま提示できるようになり、IDE の提案が読みやすくなります。追加されたテストは回帰防止を保証し、変更の意図と挙動を明確にしています。