Web production note

 【更新日 :

ViteでTailwind CSS 4系を利用する(リセットCSSの差し替えやユーティリティclassの拡張)

Category:
開発環境

ViteでTailwind CSS 4系を導入したサンプルです。
Tailwind CSS 4系の最適化(リセットCSSの差し替え、ユーティリティclassの拡張)や、独自styleと混在させることができるのか検証しました。

※本記事はTailwind CSS 4系で検証した記事です。3系を利用したい場合はこちらの記事をご参照ください。

Tailwind CSSとは

ユーティリティファーストで考案されたオープンソースのCSS フレームワークです。

flex pt-4 text-center といったようにCSSのclass名と設定されるstyleが一意のため、プロジェクト毎に依存しないコードを書くことができます。

一方でclass設定が多くなりHTMLの可読性が下がったりHTMLが肥大化するなどデメリットもあるため、利用する場合には実装要件に合わせてよく検討する必要があるかもしれません。

Tailwind CSS 4系はSass、Less、StylusなどCSS プリプロセッサと併用はできない

公式サイトで言及されていますが、Tailwind CSS 4系はscssなどと併用はできません。

※Lightning CSSが内蔵されているため、ビルド時に@importをまとめてくれるバンドル機能やscssのようにネスト構造を変換してくれる機能は備わっています。

ailwind CSS v4.0 is a full-featured CSS build tool designed for a specific workflow, and is not designed to be used with CSS preprocessors like Sass, Less, or Stylus.

Think of Tailwind CSS itself as your preprocessor — you shouldn’t use Tailwind with Sass for the same reason you wouldn’t use Sass with Stylus.

Since Tailwind is designed for modern browsers, you actually don’t need a preprocessor for things like nesting or variables, and Tailwind itself will do things like bundle your imports and add vendor prefixes.

Compatibility Sass、Less、Stylusの項目より
https://tailwindcss.com/docs/compatibility#sass-less-and-stylus

Lightning CSSの詳細は以下などをご参照ください。

Tailwind CSS 3系からその他の変更点

バージョン3で非推奨となっていたclassの削除、一部のclass名の変更、カスタムユーティリティの追加など細かい点で多くの変更があります。詳細は以下をご参照ください。

Viteのベース構築

本記事は公式ドキュメントに沿ってViteのTailwindプラグインを利用します。

ベース環境のインストールは完了していることが前提ですので基本の構築は以下の記事を参照してください。

Tailwind CSS 4系ではscssは利用できないため、htmlやその他の設定のみご参照ください。

Tailwind CSS 4系のブラウザ対応

4系のコア機能は以下のブラウザのバージョンに依存しています。

  • Chrome 111 (released March 2023)
  • Safari 16.4 (released March 2023)
  • Firefox 128 (released July 2024)

上記より古い環境にも対応が必要な場合は3系をインストールしてください。

ブラウザ対応の詳細は以下をご参照ください。

Vite環境にTailwind CSS 4系をインストール

Vite環境でターミナルを開いた後、以下のコマンドを実行します。

npm install tailwindcss @tailwindcss/vite

Viteプラグインを設定する

vite.config.js で @tailwindcss/vite のプラグインを呼び出します。

vite.config.js

import { defineConfig } from 'vite';
import tailwindcss from '@tailwindcss/vite';
~省略~
export default defineConfig({
  ~省略~

  plugins: [
    tailwindcss(),
  ],
})

style.cssで Tailwind CSSをインポートする

インポートの方法は2種類あります。デフォルト設定をそのまま利用する場合は前者の @import "tailwindcss"; を利用し、リセットCSSなど一部の設定を取り除いたり調整したい場合は後者の方法を利用してください。リセットCSSの差し替え方法などは項目を分けて後述します。

style.css

@import "tailwindcss";

style.css

@layer theme, base, components, utilities;
@import "tailwindcss/theme.css" layer(theme);
@import "tailwindcss/preflight.css" layer(base);
@import "tailwindcss/utilities.css" layer(utilities);

Tailwind CSSの利便性を上げる

VS Codeの拡張機能

VS Code上でclass名のオートコンプリートなど便利な機能が追加されるTailwind CSS IntelliSenseや、Prettierでclassを自動的に並べ替えなどしてくれるPrettier pluginなど、公式から便利な拡張機能が配信されています。詳細は以下をご参照ください。

ブラウザの拡張機能

Tailwind Cheat Sheet ExtensionはChromeの拡張機能です。ブラウザ上でプロパティ名などからTailwind CSSのclass名を検索できるので、公式のチートシートを見に行く手間を省くことができます。

リセットCSSを独自のものに差し替える

Tailwind CSSは単体でも利用できるようにデフォルトでリセットCSS(Preflight)が設定されていますが、layer(base)のインポート箇所 "tailwindcss/theme.css" を独自のリセットCSSのファイルパスに書き換えると差し替えることができます。

style.css

@layer theme, base, components, utilities;
@import "./style.cssから独自のリセットcssを参照するパス/reset.css" layer(base);
@import "tailwindcss/preflight.css" layer(base);
@import "tailwindcss/utilities.css" layer(utilities);

Tailwind CSS 4系のリセットCSSの詳細は以下をご参照ください。

テーマ(CSS変数の初期値)のカスタマイズ方法

各設定をインポートした後にテーマ変数( @theme )を記述することで、各初期値(CSS変数の値)を上書きすることができます。

style.css

@import "tailwindcss";

/* 必要な設定をインポートした後に @theme{} で設定を上書きできます。 */
@theme {
  --font-sans: "Noto Sans JP", "Hiragino Kaku Gothic ProN", "Hiragino Sans", Meiryo, sans-serif;

  --spacing: 0.625rem;

  --color-black: #101010;
}

各classが参照している変数はブラウザの検証ツールや、各プロパティのドキュメントで確認することができます。

テーマのカスタマイズ方法の詳細は以下をご参照ください。

メディアクエリのブレイクポイントを変更する

ブレイクポイントもテーマ変数( @theme )内で書き換えることができます。

style.css

@theme {
  --breakpoint-xs: 375px;
  --breakpoint-sm: 640px;
  --breakpoint-md: 782px;
  --breakpoint-lg: 1024px;
  --breakpoint-xl: 1440px;
}

詳細は以下をご参照ください。

Tailwind CSSの各classを拡張する

テーマ変数( @theme )やユーティリティ変数( @utility )を用いると既存のclassを拡張したり、独自のclassを追加したりできます。

いくつか例を記載しますが、詳細は以下の「Adding custom utilities」の項をご参照ください。

例)単色のclassを追加する

text-red-50 など色のclassは基本的に濃さの度合いもセットになっていますが、テーマ変数( @theme )に変数を追加するとtext-red など単体の色classを追加することができます。

style.css

@theme {
  --color-red: #ff0000;
}

index.html

<p class="text-red">単色のclassを追加する</p>

例)文字サイズをpxの設定値でremに変換する機能を追加する

ユーティリティ変数( @utility )で利用できる --value(integer) は、class名の末尾「*」の値が整数の場合に認識され呼び出している箇所に代入されます。

style.css

/* 既存の設定を上書き:整数値をremに変換 例)text-20 -> font-size: 1.25rem;  */
@utility text-* {
  font-size: calc(--value(integer) / 16 * 1rem);
}

index.html

<p class="text-20">pxの設定値でrem値に変換できる文字サイズのclassを追加する</p>

※css上にはcalc()を用いた計算式で記述しますが、npm run build後のstyle.cssにはLightning CSSによって計算後の値が内包されます。
例)text-20
npm run dev 実行中: .text-20 { font-size: calc(20 / 16 * 1rem); }
npm run build 後: .text-20 { font-size: 1.25rem; }

例)marginのclassにmt-1/2など分数(%変換)の機能を追加する

widthなど一部のプロパティには分数(%変換)のclass(w-1/2 → width: 50%;)が備わっていますが、これをmarignのclassにも追加してみます。

ユーティリティ変数( @utility )で利用できる --value(ratio) は、class名の末尾「*」の値が分数の場合に認識され呼び出している箇所に代入されます。

style.css

/* %変換 例) m-1/2 -> margin: 50% */
@utility m-* {
  margin:calc(--value(ratio) * 100%);
}
/* 負の値 例) -m-1/2 -> margin: -50% */
@utility -m-* {
  margin:calc(--value(ratio) * -100%);
}

/* 
  ※一括で全てのmarigin classに設定を追加する方法はないため、
  ml-やmr-など他のclassにも追加したい場合は個別に全て書いてください。
*/
@utility mt-* {
  margin-top:calc(--value(ratio) * 100%);
}
@utility -mt-* {
  margin-top:calc(--value(ratio) * -100%);
}

/* 省略 */

index.html

<p class="m-1/2">marignに分数(%変換)の機能を追加する</p>
<p class="-m-1/2">marignに分数(%変換)の機能を追加する</p>
<p class="m-123/456">分数になっていれば数値の変更は自由</p>

※css上にはcalc()を用いた計算式で記述しますが、npm run build後のstyle.cssにはLightning CSSによって計算後の値が内包されます。
例)m-1/2
npm run dev 実行中: .m-1/2 { margin: calc(1 / 2 * 100%); }
npm run build 後: .m-1/2 { margin: 50%; }

Tailwind CSSに存在しない独自のユーティリティclassを追加する

ユーティリティ変数( @utility )は、既存classの拡張だけでなく --value(integer) などを用いて独自の名称でルールを設定したり、単一のclassを生成することも可能です。

style.css

/* 整数値をremに変換する独自class 例)text-rem-20 -> font-size: 1.25rem;  */
@utility text-rem-* {
  font-size: calc(--value(integer) / 16 * 1rem);
}

/* display: flex; で上下左右中央揃えにするclassを追加 */
@utility flex-center {
  display: flex;
  justify-content: center;
  align-items: center;
}

/* ネスト構造を持っていても設定できます */
@utility iframe-wrap {
  overflow: hidden;
  position: relative;
  iframe {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
  }
}

index.html

<div class="flex-center">
  <p>エリア内の要素を上下左右中央揃えにするclass</p>
</div>
<!-- 
  iframeタグをレスポンシブ対応させるclass
  ※比率指定の併用が必要(aspect-videoはTailwind CSSに標準搭載されているclassです)
-->
<div class="iframe-wrap aspect-video">
  <iframe src=""></iframe>
</div>

独自のユーティリティclassをTailiwnd CSSのユーティリティ変数( @utility )で追加すると、build時に利用していないclassが省かれるため、cssファイルのスリム化が期待できる

独自の設定はそのままstyle.cssに追記しても動作するため、ユーティリティ変数( @utility )を利用しない場合でも表面上の動作にどちらも違いはありません。

しかし、Tailiwnd CSSのユーティリティ変数( @utility )を用いると、npm run build 時に利用していないclassを省いてくれるため、ビルド後のstyle.cssのスリム化が期待できます。

独自の設定が少なければ大した違いではありませんが、記述量が多ければ多いほど利用していない無駄なclassを省いてくれる機能の恩恵は大きくなります。

cssファイルの容量削減はページの読み込み速度対策に繋がるため、独自の拡張をする場合はなるべくユーティリティ変数( @utility )を利用した方が良さそうです。

その他の拡張オプション

列挙した例で用いたユーティリティ変数( @utility )の例はほんの一部で、この他にも多様なオプションが用意されているため、かなり柔軟にカスタマイズしたclassが作れそうです。

記載例の内容では対応できない機能を持ったclassが欲しい場合は、以下ページの「Adding custom utilities」の項をご参照ください。

hoverのメディアクエリをany-hoverに変更する(カスタムバリアント変数( @custom-variant ))

Tailwind CSS 4系でhover系のclassを npm run build すると、@media (hover: hover) {} でグループ化されますが、カスタマイズバリアント変数( @custom-variant )を用いるとこれを上書きできます。

style.css

/* npm run build後のhover系classのメディアクエリをany-hoverに変更する  */
@custom-variant hover {
  @media (any-hover: hover) {
    &:hover {
      @slot;
    }
  }
}

@media (hover: hover) {}@media (any-hover: hover) {} の違いについては以下をご参照ください。

カスタムバリアント変数( @custom-variant )で任意のルールを持ったclassの接頭辞を追加する

直上のhoverのメディアクエリのように既存の上書きも可能ですが、カスタマイズバリアント変数( @custom-variant )を用いるとmd:、hover:などとは別に任意のルールでclassの接頭辞を追加することができます。

style.css

/* 例)PCレイアウトかつ画面が横長の時のみ  */
@custom-variant side {
  @media (min-width:782px) and (max-aspect-ratio:3/1) {
    @slot;
  }
}

index.html

<p class="side:text-200">画面が横長の時のみ設定を変えるclass</p>

詳細は以下の「Adding custom variants」の項をご参照ください。

独自に記述するメディアクエリのルールでもブレイクポイントの変数を参照して保守性を上げる

Tailwind CSS 4系を使っている環境ではLightning CSSが導入されているため、CSSの新しい機能 Custom Media Queries(@custom-media)(メディアクエリの設定を変数で参照ができる機能)を用いることができますが、これが有効化されるのは npm run build 時のみです。

現段階では上記の手法で記述するとnpm run devで開発している途中にはメディアクエリが無効化されてしまい、build時とdev中で環境に齟齬が発生しコーディング進行に支障をきたしてしまいます。

※記事執筆時点での対応です。将来的にブラウザがCustom Media Queries(@custom-media)に対応した場合、この対応は不要になる可能性があります。

style.css

/* メディアクエリの設定を変数に保存し一元管理する */
@custom-media --narrow-window (max-width: 30em);

.class-name {
  font-size: 16px;
  /* 変数に保存したメディアクエリの設定を呼び出し */
  @media (--narrow-window) {
    font-size: 10px;
  }
}

※Tailwind CSSのブレイクポイント変数で設定した値は参照できないため、全ての設定を一箇所で管理することはできません。

style.css

/* 
  ※Tailwind CSSのブレイクポイントは参照できないため、
  同じ変数名にしたとしてもそれぞれ別で定義しておく必要があります。
*/

/* 独自style用のブレイクポイント設定 */
@custom-media --breakpoint-md (min-width: 782px);

/* Tailwind CSS用のブレイクポイント設定( @custom-media には利用できない) */
@theme {
  /* md:xxx のclassで用いられるブレイクポイント */
  --breakpoint-md: 782px;
}

/* 独自に記述したstyle */
.class-name {
  font-size: 10px;
  /* 
    Tailwind CSSの変数名と同じ場合でも
    ここで参照しているのは @custom-media で定義した方です。
  */
  @media (--breakpoint-md) {
    font-size: 20px;
  }
}

Custom Media Queries(@custom-media)の詳細は以下の「Custom Media Queries」の項をご参照ください。

postcss-custom-media を追加して開発中でもCustom Media Queries(@custom-media)を利用できるようにする

PostCSSのプラグイン postcss-custom-media を追加するとCustom Media Queries(@custom-media)の機能を開発環境中にも利用できるようになります。

postcss-custom-media をVite環境にインストール

npm install -D postcss-custom-media

postcss.config.cjs へ呼び出しコードを追記

ファイルが存在しない場合はvite.config.jsが存在するルートディレクトリに作成し、記述方法は環境に合わせて調整してください。

Viteは標準でPostCSSに対応しているため、postcss.config.cjsファイルを追加するのみで動作します。vite.config.js側に記述を追加する必要はありません。

postcss.config.cjs

module.exports = {
  plugins: {
    'postcss-custom-media': {},
  },
};

postcss.config.js の場合

export default {
  plugins: {
    'postcss-custom-media': {},
  },
}

package.json内に記載されていますが、Viteは "type": "module" の形式です。"type": "module" を設定すると.jsファイルはES6モジュールとして扱うようになりますが、ES6モジュールではrequire、module、exportsなどの識別子が利用できなくなります。(代わりにimportとexportが利用できます。)

“type”: “module”設定でも従来のコードを利用したい場合は、JSファイルをCommonjsモジュールとして扱うように拡張子をcjsに変更します。(”type”: “module”に関係なくES6モジュールとして扱いたいJSファイルがある場合は拡張子をmjsにします。)

本記事ではベースの構築記事でpostcss.configの拡張子を.cjsにしているため見出しはそれに合わせています。

Tailwind CSSの拡張コード(@theme、@utility)や、 Custom Media Queries(@custom-media)の変数はファイルを分割インポートしても動作する

@theme{} などの各変数も何度書いても大丈夫なため、無理に1つのファイルに集約させる必要はありません。各設定は @import で読み込んだ場合も正しく動作するため分割管理することができます。

各設定を分割インポートした例(style.css )

/* 基本の設定(リセットCSSのみ差し替え) */
@layer theme, base, components, utilities;
@import "./リセットcssを参照するパス/reset.css" layer(base);
@import "tailwindcss/theme.css" layer(theme);
@import "tailwindcss/utilities.css" layer(utilities);

/* 各設定をファイル分割して管理 */
@import "./該当cssを参照するパス/breakpoint.css";
@import "./該当cssを参照するパス/theme.css";
@import "./該当cssを参照するパス/utility.css";
@import "./該当cssを参照するパス/add-utility.css";

分割ファイルの一例(breakpoint.css )

/*
  独自に記述するstyle用のブレイクポイント変数
    使い方)
    .class-name {
      font-size: 10px;
      @media (--breakpoint-md) {
        font-size: 20px;
      }
    }
*/
@custom-media --breakpoint-md (min-width: 782px);

/* Tailwind CSS 用のブレイクポイント変数 */
@theme {
  --breakpoint-xs: 375px;
  --breakpoint-sm: 640px;
  --breakpoint-md: 782px;
  --breakpoint-lg: 1024px;
  --breakpoint-xl: 1440px;
}

分割ファイルの一例(theme.css )

/* Tailwind CSSの各classで参照する初期値の変更 */
@theme {
  --font-sans: "Noto Sans JP", "Hiragino Kaku Gothic ProN", "Hiragino Sans", Meiryo, sans-serif;
  --spacing: 0.625rem;
  --color-black: #101010;
}

分割ファイルの一例(utility.css )

/* 整数値をremに変換 例)text-20 -> font-size: 1.25rem;  */
@utility text-* {
  font-size: calc(--value(integer) / 16 * 1rem);
}

/* %変換 例) m-1/2 -> margin: 50% */
@utility m-* {
  margin:calc(--value(ratio) * 100%);
}
/* 負の値 例) -m-1/2 -> margin: -50% */
@utility -m-* {
  margin:calc(--value(ratio) * -100%);
}

分割ファイルの一例(add-utility.css )

/* display: flex; で上下左右中央揃えにするclassを追加 */
@utility flex-center {
  display: flex;
  justify-content: center;
  align-items: center;
}

/* ネスト構造を持っていても設定できます */
@utility iframe-wrap {
  overflow: hidden;
  position: relative;
  iframe {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
  }
}

独自に記述するstyleのhover設定にも自動的にany-hoverを追加する

PostCSSのプラグイン postcss-media-hover-any-hover を追加すると、独自に追記したCSSのhover設定でも自動的に @media (any-hover: hover) {} を設定してくれるようになります。

postcss-media-hover-any-hover をVite環境にインストール

npm install -D postcss-media-hover-any-hover

postcss.config.cjs へ呼び出しコードを追記

ファイルが存在しない場合はvite.config.jsが存在するルートディレクトリに作成し、記述方法は環境に合わせて調整してください。

Viteは標準でPostCSSに対応しているため、postcss.config.cjsファイルを追加するのみで動作します。vite.config.js側に記述を追加する必要はありません。

postcss.config.cjs

module.exports = {
  plugins: {
    'postcss-custom-media': {},
    'postcss-media-hover-any-hover': {},
  },
};

postcss.config.js の場合

export default {
  plugins: {
    'postcss-custom-media': {},
    'postcss-media-hover-any-hover': {},
  },
}

有効化した後は npm run build 後に自動的に @media (any-hover: hover) {} を設定してくれるようになります。

build前のcss

/* build前はそのまま書くだけ */
.hover-class {
  &:hover {
    color: red;
  }
}

build後のcss

/* build後には自動で追加される */
@media (any-hover: hover) {
  .hover-class:hover {
    color: red;
  }
}

目次 を閉じる