Did Tailwind kill CSS-in-JS? Or did CSS itself simply catch up? In any case the days of getting fancy with CSS architecture seem to be over, as the top three spots are all taken by longstanding CSS tools.
(訳) TailwindはCSS-in-JSを終わらせたのでしょうか?あるいは、CSS自体が単に追いついたのでしょうか?いずれにせよ、トップ3の座が長年使われてきたCSSツールによって占められていることから、CSSアーキテクチャに凝る時代は終わったようです。

https://2024.stateofreact.com/en-US/libraries/component-libraries/#css_tools より引用
CSS-in-JS と ゼロランタイム CSS
CSS-in-JS は、CSS を JavaScript で記述するアプローチのことです。これにより、次のメリットが得られました。
- スタイルのカプセル化: グローバル CSS で衝突しにくくする仕組みが整備されました。
- メンテナンスしやすさ: React コンポーネントの中にスタイルが書けるようになりました。
- 動的なスタイル: JavaScript 式や変数による動的なスタイルが生成可能になりました。
一方、CSS-in-JS を Web サーバーまたはブラウザーで CSS に変換すると、オーバーヘッド(本来不要なコスト、負荷)が生じることが課題になりました。
ゼロランタイム CSS では、Web アプリケーションをビルドする際に CSS を生成するので、前述のオーバーヘッドがありません。
次の CSS ツールは、ゼロランタイム CSS です。また、後半の 2 つは CSS-in-JS でもあります。
CSS Modules のサンプル
CSS Modules を使うと、スタイルがコンポーネントごとにスコープ化され、クラス名の衝突を防ぐことができます。
import styles from './App.module.css';
export default function App() {
return (
<div className={styles.container}>
<h1 className={styles.title}>CSS Modules サンプル</h1>
<div className={styles.card}>
<h2 className={styles.cardTitle}>カード 1</h2>
<p className={styles.cardText}>
CSS Modules を使うと、クラス名が自動的にユニークな名前に変換されます。
</p>
</div>
<div className={styles.card}>
<h2 className={styles.cardTitle}>カード 2</h2>
<p className={styles.cardText}>
これにより、グローバルなクラス名の衝突を防ぐことができます。
</p>
</div>
</div>
);
}
ユーティリティファースト CSS
Tailwind CSS のコンセプトとして知られており、単一の CSS プロパティと一対一対応するような CSS クラス (ユーティリティクラス) を組み合わせてスタイルする考え方です。
ユーティリティクラスは CSS-in-JS でのメリットと同じように、React コンポーネントの中にスタイルを書くことができます。
また、LLM (大規模言語モデル) によるコード生成との相性がよく、v0 のようなアプリ生成サービスでも使われています。
ユーティリティファースト CSS のサンプル
Tailwind CSS 風のユーティリティクラスを使ったサンプルです。単一の CSS プロパティに対応するクラスを組み合わせてスタイリングします。
import './styles.css';
export default function App() {
return (
<div className="p-20 max-w-800 mx-auto">
<h1 className="text-24 font-bold color-gray-900 mb-20">
ユーティリティファースト CSS
</h1>
<p className="color-gray-600 mb-32">
単一の CSS プロパティに対応するクラスを組み合わせてスタイリング
</p>
<div className="grid gap-16">
<div className="bg-white rounded-8 shadow p-16 border border-gray-200">
<h2 className="text-18 font-semibold color-primary mb-8">
カード 1
</h2>
<p className="color-gray-700 mb-12">
各クラスが単一の CSS プロパティに対応しています。
例: p-16 は padding: 16px に対応
</p>
<button className="btn btn-primary w-full">
詳細を見る
</button>
</div>
<div className="bg-white rounded-8 shadow p-16 border border-gray-200">
<h2 className="text-18 font-semibold color-success mb-8">
カード 2
</h2>
<p className="color-gray-700 mb-12">
このアプローチにより、HTML 内でスタイルが完結し、
カスタム CSS を書く必要が減ります。
</p>
<button className="btn btn-success w-full">
詳細を見る
</button>
</div>
</div>
<div className="flex gap-8 mt-24">
<span className="badge bg-primary-light color-primary">
プライマリー
</span>
<span className="badge bg-success-light color-success">
サクセス
</span>
<span className="badge bg-gray-100 color-gray-800">
デフォルト
</span>
</div>
</div>
);
}
CSS 仕様の進化
かつては Sass などの CSS プリプロセッサーが必要だった場面も CSS 構文でサポートされるように
CSS ネストとカスタムプロパティのサンプル
モダンな CSS の機能を使ったサンプルです。
import './styles.css';
export default function App() {
return (
<div className="theme-container">
<h1>CSS ネストとカスタムプロパティ</h1>
<div className="card">
<h2>テーマカラーを使用</h2>
<p>
CSS カスタムプロパティ(変数)を使うと、
テーマカラーなどを一元管理できます。
</p>
<button className="button">ボタン</button>
</div>
<div className="card highlight">
<h2>ハイライト表示</h2>
<p>
CSS ネストを使うと、Sass のように
階層構造でスタイルを記述できます。
</p>
<button className="button">ボタン</button>
</div>
</div>
);
}
まとめ
- ゼロランタイム CSS を使おう
- Tailwind CSS がおすすめ
- CSS 構文を活用しよう