CSS-in-JS

JavaScript 内で CSS を記述し、コンポーネントスコープのスタイルを実現する手法

CSSフロントエンド

CSS-in-JS とは

CSS-in-JS は、JavaScript/TypeScript 内に CSS を記述し、コンポーネントごとにスコープされたスタイルを生成する手法である。グローバルな CSS の名前衝突を防止し、スタイルとコンポーネントロジックを同じファイルで管理できる。

2014 年に Christopher Chedeau (vjeux) が Facebook での CSS の課題を発表し、CSS-in-JS の流れが始まった。

主要なライブラリ

ライブラリ 種類 特徴
styled-components ランタイム タグ付きテンプレートリテラル、動的スタイル
Emotion ランタイム styled-components 互換 + css prop
vanilla-extract ゼロランタイム TypeScript で型安全、ビルド時に CSS 生成
Panda CSS ゼロランタイム Tailwind 的なユーティリティ + 型安全
Linaria ゼロランタイム styled-components 的な記法、ビルド時抽出

ランタイム vs ゼロランタイム

// ランタイム CSS-in-JS (styled-components)
// → 実行時に <style> タグを動的に生成
const Button = styled.button<{ primary?: boolean }>`
  background: ${props => props.primary ? '#007bff' : '#6c757d'};
  color: white;
  padding: 8px 16px;
  border-radius: 4px;
`;

// ゼロランタイム CSS-in-JS (vanilla-extract)
// → ビルド時に .css ファイルを生成 (実行時コストゼロ)
export const button = style({
  background: '#007bff',
  color: 'white',
  padding: '8px 16px',
  borderRadius: '4px',
});
観点 ランタイム ゼロランタイム
パフォーマンス 実行時にスタイル生成 (遅い) ビルド時に CSS 生成 (速い)
動的スタイル props に応じて動的に変更可能 CSS 変数で対応
SSR 対応 スタイルの抽出が必要 静的 CSS なので問題なし
バンドルサイズ ランタイムライブラリが必要 CSS のみ (JS 不要)

CSS-in-JS の衰退と代替手法

2022 年頃から、ランタイム CSS-in-JS のパフォーマンス問題が広く認識され、代替手法への移行が進んでいる。

  • Tailwind CSS: ユーティリティクラスで直接スタイリング。最も人気
  • CSS Modules: ファイルスコープの CSS。Next.js のデフォルト
  • vanilla-extract: TypeScript で型安全なゼロランタイム CSS-in-JS
  • Panda CSS: Tailwind 的なユーティリティ + 型安全

React Server Components (RSC) ではランタイム CSS-in-JS が動作しないため、Next.js App Router を使う場合はゼロランタイムの手法が必須だ。

CSS-in-JS が適するケース

  • デザインシステムのコンポーネントライブラリ (動的テーマ切り替え)
  • props に応じて複雑にスタイルが変わるコンポーネント
  • 既存の styled-components プロジェクトの保守

styled-components の例

import styled from 'styled-components';

const Button = styled.button<{ primary?: boolean }>`
  background: ${props => props.primary ? '#0066cc' : '#fff'};
  color: ${props => props.primary ? '#fff' : '#333'};
  padding: 8px 16px;
  border-radius: 4px;
`;

<Button primary>送信</Button>

CSS-in-JS の関連書籍も参考になる。

関連用語