🗽

【Tailwind和訳】CUSTOMIZATION/Just-in-Time Mode

2021/10/23に公開

この記事について

この記事は、CUSTOMIZATION/Just-in-Time Modeの記事を和訳したものです。

記事内で使用する画像は、公式ドキュメント内の画像を引用して使用させていただいております。

Just-in-Time Mode (v2.1+)

Tailwind CSS v2.1+に対応した、より高速でパワフルなオンデマンドエンジンです。

Tailwind CSS v2.1 では、Tailwind CSS 用の新しいジャストインタイムコンパイラが導入されており、初期構築時にすべてを事前に生成するのではなく、テンプレートをオーサリングする際にオンデマンドでスタイルを生成します。

https://youtu.be/3O_3X7InOw8

これには多くの利点があります。

  • ビルド時間が非常に速い。 Tailwind は、CLI を使用すると初期コンパイルに 3 ~ 8 秒かかり、webpack プロジェクトでは 30 ~ 45 秒かかることがあります。このライブラリは、どんなビルドツールを使っていても、どんなに大きなプロジェクトでも約 800ms でコンパイルできます(インクリメンタル・リビルドでは 3ms)。

  • すべてのバリアントがすぐに有効になります。 focus-visible, active, disabled などのバリアントは、ファイルサイズを考慮して、通常はデフォルトでは有効ではありません。このライブラリは必要に応じてスタイルを生成するので、好きなときに好きなバリアントを使うことができます。sm:hover:active:disabled:opacity-75のように重ねて使うこともできます。バリアントの設定はもう必要ありません。

  • カスタム CSS を書かずに任意のスタイルを生成。 デザインシステムにない超特殊な値が必要になったことはありませんか?例えば、風変わりな背景画像のためにがtop:-113pxが必要になったことはありませんか?スタイルは必要に応じて生成されるので、top-[-113px]のような角括弧表記を使って、必要に応じてこのようなユーティリティを生成することができます。md:top-[-113px]のようなバリアントでも動作します。

  • 開発時と本番時の CSS は同じです。 スタイルは必要に応じて生成されるため、本番環境で使用しないスタイルをパージする必要はありません。つまり、すべての環境でまったく同じ CSS が表示されます。本番環境で重要なスタイルを誤ってパージしてしまう心配はもうありません。

  • 開発環境でのブラウザパフォーマンスの向上。 開発用のビルドは本番用のビルドと同じくらい小さいので、ブラウザはあらかじめ生成された数メガバイトの CSS を解析・管理する必要がありません。大きく拡張された構成のプロジェクトでは、開発ツールの応答性が格段に向上します。

この機能については、発表ビデオをご覧ください。


JIT モードの有効化

ジャストインタイムモードを有効にするには、tailwind.config.jsファイルでmodeオプションをjitに設定します。

tailwind.config.js
  module.exports = {
+  mode: 'jit',
    purge: [
      // ...
    ],
    theme: {
      // ...
    }
    // ...
  }

JIT モードでは、テンプレートファイルをスキャンしてオンデマンドで CSS を生成しますので、tailwind.config.jsファイルでpurgeオプションを設定して、すべてのテンプレートパスを設定することが重要です。

tailwind.config.js
  module.exports = {
    mode: 'jit',
+  // これらのパスは単なる例であり、あなたのプロジェクト構造に合わせてカスタマイズしてください。
+  purge: [
+    './public/**/*.html',
+    './src/**/*.{js,jsx,ts,tsx,vue}',
+  ],
    theme: {
      // ...
    }
    // ...
  }

これで、開発サーバーやビルドランナーを起動すると、Tailwind は事前にすべてのスタイルを生成するのではなく、オンデマンドでスタイルを生成します。

問題がありますか?よくある問題を解決する方法については、トラブルシューティングのセクションをご覧ください。


新機能

すべてのバリアントが有効

スタイルがオンデマンドで生成されるため、コアプラグインごとにどのバリアントが利用可能かを設定する必要がありません。

<input class="disabled:opacity-75" />

focus-visibleactivedisabledevenなどのバリアントを任意のユーティリティと組み合わせて、tailwind.config.jsファイルに変更を加えることなく使用することができます。

スタック可能なバリアント

すべてのバリアントは、カスタム CSS を記述することなく、非常に特定の状況を簡単にターゲットにするために組み合わせることができます。

<button class="md:dark:disabled:focus:hover:bg-gray-400"></button>

任意の値のサポート

多くのユーティリティーでは、新しい角括弧表記を用いて任意の値をサポートしており、デザインシステムからの「脱却」を示しています。

<!--サイズと位置 -->
<img
  class="absolute w-[762px] h-[918px] top-[-325px] right-[62px] md:top-[-400px] md:right-[80px]"
  src="/crazy-background-image.png"
/>

<!--色 -->
<button class="bg-[#1da1f1]">Twitterでシェアする</button>

<!--複雑なグリッド -->
<div class="grid-cols-[1fr,700px,2fr]">
  <!-- ... -->
</div>

この機能は、マーケティングサイトの背景画像を慎重に配置するなど、特定のスタイルを必要とする要素がいくつかある場合に、ピクセル単位で完璧なデザインを構築するのに非常に便利です。

将来的には、同僚がこの機能を責任を持って使うことを信用していない、パワーに飢えたチームリーダーのために、何らかの形で「strict mode」を追加する予定です。

動的な値

なお、任意の値を使用する場合は、パージ可能な HTMLを記述する必要があります。また、Tailwind が正しく検出するためには、クラスは完全な文字列として存在する必要があります。

❌  クラス名の作成に文字列の連結を使用しないでください。
<div className={`mt-[${size === "lg" ? "22px" : "17px"}]`}></div>
✅  完全なクラス名を動的に選択する
<div className={ size === 'lg' ? 'mt-[22px]' : 'mt-[17px]' </div>

Tailwind はクライアントサイドのランタイムを一切含んでいないため、クラス名はビルド時に静的に抽出可能である必要があり、また、クライアント上で変化する任意の動的な値に依存することはできません。このような状況では、インラインスタイルを使用するか、または Tailwind とEmotionのような CSS-in-JS ライブラリを組み合わせて使用してください。

❌  動的な値から任意の値を計算することはできません。
<div class="bg-[{{ userThemeColor }}]"></div>
✅  動的な値やユーザー定義の値には、インラインスタイルを使用します。
<div style="background-color: {{ userThemeColor }}"></div>

スペースを含む値

また、CSS のクラスにはスペースを含めることができないため、calc(100px - 4rem)1fr 700px 2frなどの任意の値をそのまま使用することはできませんので注意が必要です。このような任意の値をクラス名に使用するには、calcの呼び出しなどではスペースを削除し、1fr 700px 2frのようなリストではスペースをカンマに置き換える必要があります。Tailwind は、対応する CSS を生成する際に、calcの呼び出しでは自動的にスペースを再導入し、リストではコンマをスペースに置き換えます。

❌  任意の値にスペースを使わない
<div class="h-[calc(1000px - 4rem)]">...</div>
<div class="grid-cols-[1fr 700px 2fr]">...</div>
✅  必要に応じてスペースを削除したり、カンマに置き換えたりします。
<div class="h-[calc(1000px-4rem)]">...</div>
<div class="grid-cols-[1fr,700px,2fr]">...</div>

曖昧な値

CSS の変数を任意の値として使用している場合、時としてエンジンにとって曖昧なクラス名になってしまうことがあります。

<!--これはフォントサイズのユーティリティーなのか、それともテキストカラーのユーティリティーなのか?-->
<div class="text-[var(--mystery-var)]"></div>

このような場合には、任意の値の前に型名をつけることで、エンジンにヒントを与えることができます。

<div class="text-[color:var(--mystery-var)]"></div>

サポートされている型は

  • length
  • color
  • angle
  • list

組み込みの重要修飾子

任意のユーティリティーの先頭にをつけることで、重要な意味を持たせることができます。

<p class="font-bold !font-medium">CSSの中でboldが後から出てきても、これはmediumになります。</p>

!は常にユーティリティー名の先頭にあり、バリアントの後、プレフィックスの前にあります。

<div class="sm:hover:!tw-font-bold"></div>

これは、自分では制御できないスタイルとの戦いのために、特異性を高める必要があるような稀な状況で役立ちます。

色の不透明度の簡略化

bg-opacity-50text-opacity-25placeholder-opacity-40のようなユーティリティーを使用する代わりに、JIT エンジンでは、色の最後に不透明度を追加することができます。

- <div class="bg-red-500 bg-opacity-25">
+ <div class="bg-red-500/25">

これにより、Tailwind ではどこでも色の不透明度を変更することができるようになりました。例えばグラデーションのように、これまで不透明度のユーティリティーがなかった場合でもです。

<div class="bg-gradient-to-r from-red-500/50"></div>

不透明度の値は、あなたのopacityスケールから取得されますが、角括弧記法を使って任意の不透明度の値を使用することもできます。

<div class="bg-red-500/[0.31]"></div>

サイドごとのボーダーカラー

2017 年頃からリクエストされていましたが、ファイルサイズを考慮して省かれていた、要素の各サイドのボーダーカラーを独立して設定するサポートが、JIT エンジンにようやく追加されました。

<div class="border-2 border-t-blue-500 border-r-pink-500 border-b-green-500 border-l-yellow-500"><!-- ... -->
</div>

疑似要素のバリアント

JIT エンジンでは、 ::before, ::after, ::first-letter, ::first-line, ::marker, ::selectionのような擬似要素のスタイリングをサポートしています。

<div class="before:block before:bg-blue-500 after:flex after:bg-pink-300"></div>

beforeまたはafterバリアントを追加すると、要素が実際に表示されるように、contentプロパティが自動的に""に設定されます。content プロパティを変更するには、新しい content ユーティリティを使用します。

また、前述の通り、選択されたテキストにスタイルを与えることができる ::selection のような他の擬似要素もサポートしています。

<p class="selection:bg-yellow-300 ...">あなたが私を強調すると、私は黄色になります。</p>

また、 ::marker 疑似要素では、リストのマーカーにスタイルを付けることができます。

<ul class="marker:text-gray-500">
  <li>Odio et sed.</li>
  <li>Voluptatem perferendis optio est id.</li>
  <li>Accusamus et aut odit.</li>
</ul>

コンテンツユーティリティ

content プロパティを設定するための新しい content-* ユーティリティが追加されました。これは、新しい before および after バリアントとともに非常に便利です。

<div class="before:content-['hello'] before:block ..."></div>

また、attr関数のようなものもサポートしており、属性に格納された値を参照することができます。

<div data-content="hello world" class="before:content-[attr(data-content)] before:block ..."></div>

疑似クラスの徹底的なサポート

hoverfocusなどの既存のものに加えて、requiredinvalidplaceholder-shownなど、意味があると思われるすべての擬似クラスのサポートを追加しました。

<input class="invalid:border-red-500 ..." />

新しい擬似クラスのバリエーションの全リストは以下の通りです。

  • onlyonly-child のため)
  • first-of-type
  • last-of-type
  • only-of-type
  • target
  • default
  • indeterminate
  • placeholder-shown
  • autofill
  • required
  • valid
  • invalid
  • in-range
  • out-of-range

キャレットカラーユーティリティー

新しいcaret-{color}ユーティリティーを使って、フォームフィールド内のカーソルの色を設定できるようになりました。

<input class="caret-red-500" />

これらは、tailwind.config.jsファイルのthemeセクションにあるcaretColorキーを使ってカスタマイズできます。

シブリングセレクタのバリアント

親の状態に基づいて要素のスタイルを決めるために長年サポートしてきたgroup-*バリアントと同様に、新しいpeer-*バリアントを使って、前の兄弟の一つの状態に基づいて要素のスタイルを決めることができます。

<label>
  <input type="checkbox" class="peer sr-only" />
  <span class="h-4 w-4 bg-gray-200 peer-checked:bg-blue-500">
    <!-- ... -->
  </span>
  <!-- ... -->
</label>

興味のある前の兄弟を peer クラスでマークし、peer-hoverpeer-checkedpeer-focus などのバリアントを使用して、その兄弟の状態に基づいて要素をスタイリングするだけです。

単純化されたトランスフォーム、フィルタ、およびバックドロップフィルタの構成

transformfilterbackdrop-filter クラスは、それぞれの合成可能なユーティリティーを「有効にする」ために必要ではなくなりました。

- <div class="transform scale-50 filter grayscale backdrop-filter backdrop-blur-sm">
+ <div class="scale-50 grayscale backdrop-blur-sm">

これで、関連するサブユーティリティを使用するたびに、これらの機能が自動的に有効になります。


変更点

JIT エンジンは、Tailwind CSS v3.0 として出荷する予定のもののプレビューであると考えています。そのため、オプトインする際に考慮すべきいくつかの小さな変更点があります。これらの変更が多くの人に影響を与えるとは考えていませんが、特にプロジェクトの見栄えに微妙な違いがあることに気付いた場合には、読む価値があります。

バリアントは一緒に表示されます

クラシック・エンジンでは、ユーティリティーのバリアントは、ユーティリティーごとに生成される CSS の中で、次のようにまとめられます。

/* クラシックエンジン */

.bg-black {
  background-color: #000;
}
.hover\:bg-black:hover {
  background-color: #000;
}
.focus\:bg-black:focus {
  background-color: #000;
}

/* ... */

.opacity-75 {
  opacity: 0.75;
}
.hover\:opacity-75:hover {
  opacity: 0.75;
}
.focus\:opacity-75:focus {
  opacity: 0.75;
}

/* ... */

.translate-x-4 {
  --tw-translate-x: 1rem;
}
.hover\:translate-x-4:hover {
  --tw-translate-x: 1rem;
}
.focus\:translate-x-4:focus {
  --tw-translate-x: 1rem;
}

JIT エンジンでは、バリアントごとにグループ化されます。

/* JITエンジン */

.bg-black {
  background-color: #000;
}
.opacity-75 {
  opacity: 0.75;
}
. .translate-x-4 {
  --tw-translate-x: 1rem;
}

/* ... */

.hover\:bg-black:hover {
  background-color: #000;
}
.hover\:opacity-75:hover {
  opacity: 0.75;
}
.hover\:translate-x-4:hover {
  --tw-translate-x: 1rem;
}

/* ... */

.focus\:bg-black:focus {
  background-color: #000;
}
.focus\:opacity-75:focus {
  opacity: 0.75;
}
.focus\:translate-x-4:focus {
  --tw-translate-x: 1rem;
}

つまり、コアプラグインごとにバリアントの順序を指定することはできなくなりました - すべてのユーティリティでバリアントは常に同じ順序になります。これは、例えば特定のユーティリティーでfocusを打ち消すためにhoverが必要で、バリアントリストでfocusの後にhoverが来るようにしていた場合に問題となる可能性があります。

tailwind.config.js
  module.exports {
    // バリアントの設定(順序を含む)は、JITエンジンによって尊重されません。
-   variants: {
-    // ...
-    backgroundColor: ['focus', 'hover']
-  }
  }

このような状況を JIT エンジンで処理するには、代わりに stacked variants を使うことをお勧めします。

<!-- これにより、たとえフォーカスされていても、ホバー時に要素が青くなることが保証されます -->
<div class="focus:bg-red-500 hover:bg-blue-500 hover:focus:bg-blue-500"></div>

Stacked variants では、複数の variant が同時に有効な場合のスタイルを指定することができます。したがって、focusのスタイルをhoverのスタイルで上書きしようとするのではなく、hoverfocusの両方が同時に有効な場合の要素の外観を明示的に宣言します。

バリアントは @tailwind バリアントに挿入される

クラシック・エンジンでは、すべてのユーティリティー・バリアントは、@tailwind utilitiesディレクティブの一部として注入されます。

JIT エンジンでは、バリアントは @tailwind screens から名前を変えた @tailwind variants ディレクティブで注入されます。

このディレクティブは (@tailwind screens が以前からそうであったように) 任意であり、ユーティリティーのバリアントが注入される場所を明示的に制御したい場合にのみ有用です。デフォルトでは、ユーティリティー・バリアントは常にスタイルシートの一番最後に注入されます。

もし、以前に@tailwind screensを使っていたのであれば、@tailwind variantsを使うようにコードを更新してください。

  @tailwind base;
  @tailwind components;
  @tailwind utilities;
+ @tailwind screens;
- @tailwind variants;

  /* いくつかのカスタムCSS... */

この@tailwind variants機能は、高度なエスケープハッチと考えられており、デフォルトでは省略することをお勧めします。これは、非常に脆弱な既存の CSS コードベースを持つレガシーなシステムに Tailwind を導入する場合にのみ当てはまり、動作させるためにスタイルシートの最後に絶対に必要なスタイルがある場合です。

トランスフォームとフィルタは、明示的に有効にする必要はありません。

JIT エンジンを使用する場合、transformfilterbackdrop-filter クラスは、これらの機能を「有効」にするためには必要ありません。

- <div class="transform scale-50 filter grayscale backdrop-filter backdrop-blur-sm">
+ <div class="scale-50 grayscale backdrop-blur-sm">

つまり、transformfilter がデフォルトでは休止状態で、transformfilterbackdrop-filter を追加することで条件付きで有効になるということは、もはや期待できないということです。

その代わりに、サブユーティリティー自体にバリエーションを持たせることになります。

- <div class="scale-105 -translate-y-1 hover:transform">
+ <div class="hover:scale-105 hover:-translate-y-1">

制限事項

この新しいエンジンは、従来のエンジンに搭載されていたほぼすべての機能をサポートしており、さらに、すべてを前もって生成しなければならない場合には不可能だった数多くの新機能も搭載しています。

しかし、エンジンの動作の性質上、現時点では不可能なことがいくつかあります。

  • safelistオプションは、正規表現をサポートしていません。 デフォルトでは CSS が生成されないため、セーフリストは完全なクラス名のリストでなければなりません。正規表現にマッチするクラス名のリストがあらかじめ生成されていないため、正規表現をセーフリストにすることはできません。

  • 関数として設定されている場合、prefixオプションは完全なクラス名を検出できません。 事前にクラス名を生成していないため、カスタムプレフィックス関数にはユーティリティーの「namespace」を渡すことしかできません。例として、このコメントを参照してください。

  • コアの一部であるか、プラグインによって生成されたか、@layerルールの中で定義されたクラスのみを@applyすることができます。 現在のところ、@layerルールで定義されていない任意の CSS クラスを@applyすることはできませんが、将来的にはサポートする予定です。

また、特定のビルドツールとの互換性の問題についても解決中です。これは、問題追跡システムで追跡できます。

その他の問題やバグを発見された場合は、イシューをオープンしていただければ修正いたします。


トラブルシューティング

クラスを削除してもスタイルが削除されない

JIT エンジンがウォッチモードで動作している場合、HTML にクラスを追加した後にクラスを削除しても、そのクラスが CSS に残っていることに気づくことがあります。

これはバグではなく、意図的なパフォーマンスの最適化であり、特に大規模なプロジェクトにおいて、インクリメンタル・リビルドの速度を飛躍的に向上させます。

本番環境にデプロイする前には、必ず CSS を別のワンオフビルドでコンパイルし、出力をミニマイズすることをお勧めします。Next.js のような最新のツールでは、コンパイルされた CSS がバージョンコントロールにコミットされることはありませんので、このようなことは自動的に行われます。

ウォッチモード中に CSS を完全にゼロから再構築したい場合は、tailwind.config.jsファイルや CSS 入力ファイルを保存すると、すべてのキャッシュが無効になり、新たに再構築されます。

コンテンツファイルを保存してもスタイルが更新されない

Tailwind CSS v2.2+では、JIT エンジンが PostCSS のディレクトリ依存性メッセージに依存して、コンテンツファイルを CSS ビルド依存性としてビルドツールに登録します。これらは PostCSS のかなり新しい追加機能(2021 年 5 月に追加)であり、すべてのビルドツールがまだサポートするように更新されていません。

コンテンツファイルを変更しても CSS が再構築されない場合は、ウォッチスクリプトの一部としてTAILWIND_MODE=watchを設定して、Tailwind に代わりにレガシーな依存関係の追跡戦略を使用するように指示してみてください、これは多くのビルドツールでうまく機能します。

例えば、postcss-cliを使用している場合、dev/watch スクリプトでTAILWIND_MODE=watchを設定します。

package.json
{
  // ...
  scripts: {
    // 開発サーバーの起動時にTAILWIND_MODE=watchを設定する
    "dev": "TAILWIND_MODE=watch postcss -i tailwind.css -o build.css --watch",

    // 単発のビルドにはTAILWIND_MODEを設定しない
    "build": "postcss -i tailwind.css -o build.css",
    // ...
  },
  // ...
}

Windows をお使いの方は、スクリプトで環境変数を設定する際に、cross-envをお勧めします。

TAILWIND_MODE=watch を設定すると、バックグラウンドで長時間実行される監視プロセスが開始されるため、単発のビルドを行う際にこの環境変数を設定すると、ビルドが停止しているように見えることに注意してください。TAILWIND_MODE=watchを設定するのは、実際に開発サーバー/ウォッチプロセスを実行しているときだけにしてください。

スタイルが無限ループで再構築される

CSS が無限ループで再構築されているように見える場合は、ビルドツールが依存関係を登録する際に PostCSS のglobオプションをサポートしていないことが原因である可能性があります。

多くのビルドツール(webpack など)はこのオプションをサポートしておらず、その結果、特定のファイルやディレクトリ全体を監視するように指示することしかできません。例えば、webpack にディレクトリ内の*.html ファイルだけを監視するように指示することはできません。

つまり、CSS を構築することでそれらのディレクトリ内のファイルが変更された場合、変更されたファイルがグロブ内の拡張子と一致しなくても、再構築がトリガーされるということになります。

taiwind.config.js
module.exports = {
  purge: [
    // あなたのCSSは、`src`にある*あらゆる*ファイルが変更されると、再構築されます。
    './src/**/*.{html,js}',
  ],
  // ...
}

つまり、src/**/*.htmlの変更を監視しているのに、CSS 出力ファイルをsrc/css/styles.cssに書いている場合、ツールによっては無限の再構築ループが発生してしまいます。

理想的には、コンソールでこの問題を警告することができますが、多くのツールでは完全にサポートされており(当社の CLI ツールを含む)、使用しているビルドツールを検出する信頼できる方法がありません。

この問題を解決するには、いくつかの選択肢があります。

  1. purge設定で、より具体的なパスを使用します。 CSS のビルド時に変更されないディレクトリのみを含めるようにしてください。
tailwind.config.js
  module.exports = {
    purge: [
-     './src/**/*.{html,js}',
+     './src/pages/**/*.{html,js}',
+     './src/components/**/*.{html,js}',
+     './src/layouts/**/*.{html,js}'
+     './src/index.html',
    ],
    // ...
  }

必要に応じて、実際のプロジェクトのディレクトリ構造を調整して、CSS ファイルやマニフェストファイルなどの他のビルド成果物を誤って捕捉することなく、テンプレートファイルをターゲットにできるようにします。

  1. PostCSS グロブをサポートするビルドツールを使用する。 パージ設定やディレクトリ構造をどうしても変更できない場合は、完全な glob サポートを備えたツールを使って CSS を個別にコンパイルするのが最善の方法です。Tailwind CLIは、Tailwind を使って CSS をコンパイルするための、高速でシンプルな専用ツールですので、ご利用をお勧めします。

正常に動作しない場合

もし、出力に奇妙で説明しがたい問題があったり、まったく機能していないように見える場合は、お使いのビルドツールが PostCSS の依存性メッセージを適切に(あるいはまったく)サポートしていないことが原因である可能性が高いでしょう。現在、この例として知られているのがStencilです。

このような問題が発生した場合、既存のツールに Tailwind を統合するのではなく、Tailwind CLI ツールを使用して CSS を個別にコンパイルすることをお勧めします。

npm-run-allconcurrentlyのようなパッケージを使って、以下のようなスクリプトをプロジェクトに追加することで、通常の開発コマンドと一緒に CSS をコンパイルすることができます。

package.json
{
  // ...
  "scripts": {
    "dev": "npm-run-all --parallel dev:*",
    "dev:parcel": "parcel serve ./src/index.html",
    "dev:css": "tailwindcss -o src/tailwind.css -w",
    "build": "npm-run-all build:css build:parcel",
    "build:parcel": "parcel build ./src/index.html",
    "build:css": "tailwindcss -o src/tailwind.css",
  },
}

いずれにしても、既存の問題をチェックするか、新しいイシューをオープンしてください。そうすれば、私たちは問題を解明し、お使いのツールとの互換性を高めることができます。

現在、既知の互換性問題があるツールは以下の通りです。

Discussion

ログインするとコメントできます