Tailwind CSSでz-index定数化したら効かない!?
はじめに
z-[60]
みたいにz-indexをベタ書きしてたら、「これ、数が増えたときにどこの高さに何があるか絶対わからんくなるな…」って思ったんで、定数ファイルで一元管理しよう!
それで、className={`z-[${Z_INDEX.MODAL}]`}
みたいにテンプレートリテラルでクラス名を組み立ててみたら、なぜかスタイルが全く適用されなくて...。z-[60]
って直書きしてたときは動いてたのになんで!?ってハマってました。
この記事では、この現象がなぜ起こるのかとどうやって解決したかについて書いてます。
結論:なぜスタイルが効かないのか
原因は、**「Tailwindのコンパイラが、ビルド時にコードをテキストとして読んでるだけで、JavaScriptを実行して変数の中身まで見てくれるわけじゃないから」**でした。
要するに、Tailwindは俺らが書いたコードを "読んでる" だけで、"実行" はしてくれないってことです。
なので、最終的には、tailwind.config.js
のsafelist
に登録することで解決しました。
Tailwind CSSのCSS生成プロセス
もうちょい詳しく見ていきます。
Tailwindの裏ではJIT (Just-In-Time) コンパイラってやつが動いてて、必要なCSSだけを効率よく作ってくれる賢い仕組みになってます。
具体的にはこんな感じです。
-
コードを監視: まず、
tailwind.config.js
で指定されたファイル(.tsx
とか)をずっと見てる。 -
クラス名っぽい文字列を探す: ファイルが更新されたら、その中から
bg-blue-500
とかz-[60]
みたいな文字列を全部探し出す。 - CSSを生成: 見つけ出した文字列に合うCSSだけを作って、1つのファイルにまとめてくれる。
ここでのポイントは、あくまでソースコードをテキストとして見てるだけってこと。JavaScriptを実行して、Z_INDEX.MODAL
が最終的に60
になる、なんてことは知らないんです。
問題のコードで何が起きているか
これが今回の問題のコードです。
// constants/zIndex.ts
export const Z_INDEX = {
MODAL: 60,
} as const;
// components/Modal.tsx
import { Z_INDEX } from '@/constants/zIndex';
const Modal = () => {
return (
// このクラス名はTailwindには解釈できない
<div className={`fixed inset-0 z-[${Z_INDEX.MODAL}] bg-black/50`}>
{/* ... */}
</div>
);
};
ビルドの時、Tailwindのスキャナがこのコードを読んでも、className
の中にあるのはz-[${Z_INDEX.MODAL}]
っていう文字列のパターンだけ。
スキャナからすると、
「
z-[]
ってパターンはあるけど、中身は${Z_INDEX.MODAL}
?これが60
になるのか100
になるのかはわからん!だから無視しとこ!」
って感じで、z-[60]
に対応するCSSが作られず、スタイルが適用されない...ってことだったんですね。
解決策
この問題を解決するには、ビルドの時にTailwindのスキャナが「あ、このクラス名ね!」ってわかるようにしてやる必要があります。
tailwind.config.js
のsafelist
に登録することで解決しました。
これは、「このクラス、後で動的に使うから、ソースコードの中に見当たらなくても絶対CSSに入れといて!」ってTailwindに**"予約"**しとくための設定みたいなもんです。
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
'./src/**/*.{js,ts,jsx,tsx,mdx}',
],
// ↓ ここにsafelistを追加
safelist: [
'z-[1]',
'z-[50]',
'z-[60]', // MODAL用のz-index
'z-[70]',
],
theme: {
extend: {},
},
plugins: [],
}
これを設定しておけば、className={\
z-[${Z_INDEX.MODAL}]`}` って書き方でもちゃんとスタイルが当たるようになります。
👍 良いところ:
- クラス名を動的に作れるようになる。
- やりたかった定数での管理が続けられる。
🤔 注意点:
- 使うクラスが増えるたびに、この
safelist
も更新してやる必要がある。 - あれもこれもって追加しすぎると、CSSのファイルがデカくなる可能性がある。
まとめ
- Tailwindはビルドの時、コードをテキストとしてしか見てない。
- だから、テンプレートリテラルの中の変数は解読できなくて、CSSが作られない。
- 解決するには、クラス名を直書きするか、
safelist
に「これ使うよ!」って予約しとく。
この仕組みさえ分かっておけば、もう同じことでハマることもなくなるはずです。
Discussion