Fractional opacity modifiers for named shadow sizes
Tailwind CSS の影ユーティリティは、整数だけでなく小数点を含む不透明度修飾子も公式にサポートできるようになりました。これにより shadow-sm/12.5 や drop-shadow-sm/12.5 といったクラスが期待通りの CSS を生成します。
背景
Tailwind CSS の shadow-*、text-shadow-*、drop-shadow-*、inset-shadow-* は、/ で始まる不透明度修飾子を受け取る仕様になっている。 しかし、named size の分岐では isPositiveInteger(candidate.modifier.value) が使用されていたため、小数点を含む修飾子 (例: /12.5) が無視されていた。 この結果、shadow-sm/12.5 は shadow-sm と同等の出力になり、drop-shadow-sm/12.5 は CSS が生成されないという不具合が生じていた。
一方、カラー指定のブランチは共通ヘルパー isValidOpacityValue を通すため、shadow-red-500/12.5 のような fractional 修飾子は正しく color‑mix に変換されていた。 同様のロジックが影ユーティリティの named size に欠落していたことが、挙動の不整合を引き起こしていた。 この不整合は CHANGELOG で透明度制御が明示されているにも関わらず、実装が追随していなかった点が根本原因である。
技術的な変更
本修正では、packages/tailwindcss/src/utilities.ts における shadow、text-shadow、drop-shadow、inset-shadow の four utility 定義の opaque 判定ロジックを isPositiveInteger から isValidOpacityValue へ置き換えた。 この差し替えにより、小数点を含む修飾子も有効な opacity 値として認識され、alpha が正しく生成される。 結果として、shadow-sm/12.5 などの named size が期待通りの CSS を出力するようになった。
変更前:
- if (isPositiveInteger(candidate.modifier.value)) {
- alpha = `${candidate.modifier.value}%`
- }
変更後:
+ if (isValidOpacityValue(candidate.modifier.value)) {
+ alpha = `${candidate.modifier.value}%`
+ }
同時に、packages/tailwindcss/src/utilities.test.ts に regression テストを追加し、fractional 修飾子が全四ユーティリティで正しく処理されることを検証した。 テストは pnpm --filter tailwindcss exec vitest run で実行し、修正前は失敗、修正後はパスすることを確認した。 全体のテストスイートは 4685 件がパスし、回帰は検出されなかった。
設計判断
修正は既存の isValidOpacityValue ヘルパーを再利用する方針で実装された。 この選択は、他の opacity 系ユーティリティ(bg-*、text-* など)で既に採用されているロジックと一貫性を保ち、追加のユーティリティ関数を導入するコストを回避した。 また、整数限定の isPositiveInteger を除外することで、既存の整数修飾子 (/50) もそのまま動作し、後方互換性が維持された。
drop-shadow-* の named size では、修飾子が解決できない場合に if (candidate.modifier && !alpha) return が utility 全体の生成を中止していたが、alpha が正しく設定されるようになることでこの guard が自然に通過し、CSS が生成されるようになった。 追加の条件分岐変更は行わず、既存ロジックのみを修正した点が設計上のミニマリズムを示す。 これにより、コードベースのシンプルさと可読性が保持された。
まとめ
この PR により、Tailwind CSS の影ユーティリティは整数だけでなく fractional な不透明度修飾子もサポートし、shadow-sm/12.5 や drop-shadow-sm/12.5 が正しい CSS を生成できるようになった。 既存の挙動は変更せずに機能拡張が実現されたため、利用者は既存クラスをそのまま使い続けながら、細かな透明度調整が可能になる。 今後の拡張やカスタムプラグインでも同一 isValidOpacityValue ロジックを活用できる基盤が整備された。