Tailwind CSSをv3からv4にしたときに遭遇した事象と対処法

## この記事の概要

2025年1月22日にTailwind CSSのv4が正式にリリースされました。

https://tailwindcss.com/blog/tailwindcss-v4

この記事を執筆している2025年2月16日現在、私は合計4つのサイトでv3からv4へアップグレードを実施しています。

公式から提供されているアップグレードツールで事足りる部分も多いですが、一部は手動で変更しないといけませんでした。

私が遭遇した問題と、その対処法について記事にします。

:::note warn
対応したサイトがReact, Svelte, Astroと色々なパターンがあったため、特定のフレームワークや条件でだけ起きる問題というのもあると思います。
調べて分かっている分は記載しますが、漏れがあったらすみません。
:::

## 遭遇した事象

### `@reference`は自動で挿入されない

VueやSvelte、Astroを使用している場合、ファイルの中に`<style>`を定義してスタイルを当てていることがあると思います。

`<style>`内で`@apply`を使用している場合、v4では`@reference`を使用し、エントリーポイントのCSSを指定する必要があります。

https://tailwindcss.com/docs/upgrade-guide#using-apply-with-vue-svelte-or-css-modules

自動アップグレードではこちらに対応してくれないため、手動で挿入する必要がありました。

余談ですが、先ほどのリンクにあるように`@apply`を使用せずにCSSカスタムプロパティを使う書き方もあるものの、その方が時間はかかりそうな印象です。

### `theme`関数の挙動が変わり、自動で変更されない

もともと、このようなクラスを書いていました。

```html
<div class="grid-cols-[minmax(0,theme('width.60'))_1fr]">
```

この書き方だとまったくスタイルがあたらず、以下のリンクの内容を参考にしつつ書き換えました。

https://tailwindcss.com/docs/functions-and-directives#theme-function

```html
<div class="grid-cols-[minmax(0,theme(spacing.60))_1fr]">
```

この書き方だと、スタイルは当たるのですが**自分で定義し直したspacingの値ではなく、デフォルトのspacingの値**をもとにスタイルが生成されていました。

意図した挙動なのかそうでないのかは分かりませんが、自分で定義した`spacing`の値を使うにはこのように書けば大丈夫でした。

```html
<div class="grid-cols-[minmax(0,calc(var(--spacing)*60))_1fr]">
```

若干冗長になった感じと「そもそも`theme`関数を使わなくなっちゃってるじゃん」という感じはしますが、やりたいことはこれで実現できています。

### エントリーポイントのhtmlが自動クラス名抽出の対象にならない

:::note
今のところ、この挙動はSvelteKitでのみ起こっています。
:::

v3までは`tailwind.config.js`に`content: ["./src/**/*.{html,js}"]`のような指定をする必要がありましたが、v4からは指定せずとも自動でクラス名を抽出してくれるようになりました。

なりましたが、SvelteKitの`src/app.html`に書いたクラスは抽出の対象になりませんでした。

そのため`src/app.css`に以下の指定を追加する必要があります。

```diff_css:src/app.css
  @import "tailwindcss";
+ @source "./app.html";
```

ちなみに以下のドキュメントにあるように、`node_modules`など`.gitignore`で除外されているものを対象に取りたいとき使うのがメインの使い方なようです。

https://tailwindcss.com/docs/functions-and-directives#source-directive

https://tailwindcss.com/docs/detecting-classes-in-source-files#explicitly-registering-sources

### `leading-tight`などがドキュメントから消えているがこれまで通り使用できる

私のドキュメントの見方がおかしいのかもしれませんが……。

以下はv4のドキュメントで、

https://tailwindcss.com/docs/line-height

以下はv3のドキュメントです。

https://v3.tailwindcss.com/docs/line-height

予約語（？）っぽい`leading-`クラスは`leading-none`以外記載がなくなっているように見えるのですが、以下のデフォルトテーマ変数を見るとちゃんと登録されています。

https://tailwindcss.com/docs/theme#default-theme-variable-reference

クラス名としては`leading-tight`でも`text-lg/loose`のような記法でも、問題なく使えました。

### 独自の`shadow`や`rounded`を定義しているとアップグレードツールの挙動で齟齬が起きる

v4では一部のユーティリティがリネームされました。

https://tailwindcss.com/docs/upgrade-guide#renamed-utilities

アップグレードツールを使うと、これに沿ってクラス名の`shadow`を`shadow-sm`へ、`shadow-sm`を`shadow-xs`のように変換してくれます。

ただ、アップグレードツールは同時に`tailwind.config.js`に記載されていたtheme変数を`global.css`のようなファイルに転記してくれるのですが、このときに齟齬が起きます。

自前で`shadow`を定義していた場合、以下のようになります。

```css:global.css
--shadow: 独自の値;
```

つまり、**クラス名は`shadow-sm`に変わっているのに変数定義が`shadow`になってしまい**、サイト中の影が消えます。

対策としては`global.css`の命名を`--shadow-sm`に変えるだけですが、微妙に原因の分かりづらい挙動だと思いました。

### theme変数にキャメルケースを使っていると、CSSカスタムプロパティはリネームされるのにクラス名にはリネームされない

`tailwind.config.js`にて、このような設定をしていました。

```javascript:tailwind.config.js
module.exports = {
  theme: {
    colors: {
      surface: "#fff",
      surfaceVariant: "#edeeee",
      ...
    }
  }
}  
```

この場合、`bg-surfaceVariant`などのクラス名でカスタムした値を利用できます。

---

アップグレードツールを使うと、このように変換されました。

```css:global.css
@theme {
  --color-surface: #fff;
  --color-surface-variant: #edeeee;
  ...
}
```

この場合、クラス名を`bg-surfaceVariant`から`bg-surface-variant`に変更しないといけないのですが、アップグレードツールはそうしてくれませんでした。

両方変換するか、両方触らずにいてくれたら楽なのですが……。

もしかしたら`tailwind.config.js`の時点で`surfaceVariant`を`""`で括っていたら変換されずに済んだのかもしれませんが、検証できていません。