フロントエンド - CSS・スタイリング

CSS-in-JS しーえすえすいんじぇいえす

スタイリングコンポーネントstyled-componentsEmotionスコープJavaScript
CSS-in-JSについて教えて

簡単に言うとこんな感じ!

CSSのスタイル(見た目のデザイン)を、JavaScriptのコードの中に直接書いちゃう手法だよ!「このボタンのデザイン」と「このボタンの動き」を同じファイルにまとめて書けるから、パーツごとにデザインを管理しやすくなるんだ!


CSS-in-JSとは

CSS-in-JSとは、Webページのスタイル(見た目・デザイン)を定義するCSSを、JavaScriptのコードの中に記述するアプローチの総称です。従来はHTMLファイル・CSSファイル・JavaScriptファイルをそれぞれ別に管理するのが一般的でしたが、CSS-in-JSではスタイルをJavaScriptのロジックと同じファイルにまとめて書きます。

ReactやVueのようなコンポーネント(部品)ベースの開発が主流になるにつれて、「このコンポーネントに対応するスタイルはここ」と一対一で管理したいニーズが高まりました。CSS-in-JSはそのニーズに応えるために生まれた手法で、styled-componentsEmotionといったライブラリが広く使われています。

スタイルがJavaScriptの変数関数と同じ場所に書かれるため、動的なスタイル変更(ボタンが押されたら色が変わる、など)もシンプルに実装できます。一方で、実行時にスタイルを生成するためパフォーマンスへの影響も議論されており、メリット・デメリットを理解した上で採用を判断することが重要です。


CSS-in-JSの仕組みと特徴

CSS-in-JSの主なメリット・デメリットを整理します。

特徴内容
スコープの閉じ込め自動生成されたクラス名でスタイルが他のコンポーネントに漏れない
動的スタイルPropsや状態に応じてスタイルをJavaScriptで変化させられる
コロケーションデザインとロジックを同じファイルで管理できる
デッドコード排除使われていないスタイルは自動的に含まれない
実行時コストブラウザでJSを実行してCSSを生成するためパフォーマンスに影響が出る場合がある
学習コスト独自の記法やライブラリへの習熟が必要

styled-componentsの記法例

import styled from 'styled-components';

// ボタンコンポーネントにスタイルを直接定義
const Button = styled.button`
  background: ${props => props.primary ? '#1e3a8a' : '#dbeafe'};
  color:       ${props => props.primary ? '#fff'    : '#1e3a8a'};
  padding: 0.5rem 1.2rem;
  border-radius: 6px;
  border: none;
  cursor: pointer;
`;

// 使う側はただのコンポーネントとして扱える
<Button primary>送信</Button>
<Button>キャンセル</Button>

主要ライブラリの比較

ライブラリ動作タイミング特徴
styled-components実行時(Runtime)テンプレートリテラルで書けて直感的
Emotion実行時(Runtime)柔軟性が高く、styled-componentsと互換性あり
vanilla-extractビルド時(Zero-runtime)TypeScript型安全、パフォーマンス重視
Linariaビルド時(Zero-runtime)styled-componentsライクな書き方でゼロランタイム

歴史と背景

  • 2014年: FacebookエンジニアのChristopher Chedeau(vjeux)がCSS設計の課題(グローバル汚染・スコープの難しさなど)を発表し、CSS-in-JSというコンセプトが注目を集め始める
  • 2016年: styled-componentsリリース。テンプレートリテラルでCSSを書けるAPIが革新的として広まる
  • 2017年: Emotion が登場し、パフォーマンス改善版として普及
  • 2019〜2020年: コンポーネント設計の普及とともにCSS-in-JSが本格的にデファクトのひとつへ
  • 2021年〜: サーバーサイドレンダリング(SSR)やEdge環境でのパフォーマンス問題が議論され始め、Zero-runtime CSS-in-JS(ビルド時にCSSを生成する手法)への移行が進む
  • 2023年〜: Next.js App RouterなどのRSC(React Server Components)環境では実行時CSS-in-JSが動かないケースが増え、vanilla-extractやTailwind CSSなどへの移行も加速

従来のCSS管理手法との比較

CSS-in-JS以外にもCSSを管理する方法はいくつかあります。どれが最適かはプロジェクトの規模・チームの習熟度・使用フレームワークによって変わります。

CSS管理手法の比較 グローバルCSS CSS Modules CSS-in-JS Utility CSS スコープ スコープ スコープ スコープ グローバル(汚染しやすい) ファイル単位でスコープ コンポーネント単位 クラス名で制御 動的スタイル: △ 動的スタイル: △ 動的スタイル: ◎ 動的スタイル: ○ 学習コスト: 低 学習コスト: 低〜中 学習コスト: 中〜高 学習コスト: 低〜中 代表: plain CSS 代表: CSS Modules 代表: styled-components 代表: Tailwind CSS SSR: ◎ SSR: ◎ SSR: 要注意 SSR: ◎ ◎=得意 ○=対応可 △=工夫が必要 SSR = サーバーサイドレンダリング(Next.jsなどでの利用時) React Server Components環境では実行時CSS-in-JSが使えない場合がある

Runtime vs Zero-runtime の違い

CSS-in-JSの中でも近年は「いつCSSを生成するか」が重要な選択肢になっています。

【Runtime CSS-in-JS】
  ブラウザ上でJSが実行される
  → その場でCSSを生成してDOMに挿入
  → 動的な変更に強いがパフォーマンスコストあり
  例: styled-components, Emotion

【Zero-runtime CSS-in-JS】
  ビルド時(開発者のPC上)にCSSを生成
  → 通常の .css ファイルとして出力
  → ブラウザでのJSコストほぼゼロ
  例: vanilla-extract, Linaria

関連用語

  • コンポーネント — UIを部品単位で管理するReact/Vueの設計概念
  • CSS Modules — ファイル単位でCSSのスコープを閉じ込める標準的な手法
  • Tailwind CSS — ユーティリティクラスを組み合わせてスタイリングするフレームワーク
  • React — Facebookが開発したコンポーネントベースのUIライブラリ
  • サーバーサイドレンダリング(SSR) — サーバー側でHTMLを生成して返す手法。CSS-in-JSとの相性が課題になりやすい
  • Next.js — Reactベースのフルスタックフレームワーク。RSC環境でCSS-in-JSの選択に影響あり
  • Sass / SCSS — CSSを拡張した従来型のスタイルシート言語
  • ビルドツール — WebpackやViteなど、JSやCSSをまとめて最適化するツール