ゼロランタイム CSS-in-JS:開発体験と最高のパフォーマンスを両立する
1. CSS-in-JS という「諸刃の剣」
styled-components や Emotion などの CSS-in-JS は、JavaScript/TypeScript ファイル内に CSS を記述できるようにし、コンポーネント開発におけるスタイル管理を一変させました。多くの利点があります。
- コンポーネントスコープ: デフォルトでスタイルがコンポーネントに結び付くため、CSS のグローバルな名前衝突を解決します。
- 動的スタイル: コンポーネントの props や state に基づく動的なスタイルを簡単に作成できます。
- コードの同居: スタイルとコンポーネントロジックを同じファイルに置けるため、保守と整理が容易になります。
しかし、これらの利便性にコストがないわけではありません。従来の CSS-in-JS ライブラリの中心には ランタイム(Runtime) があります。コンポーネントがブラウザにマウントされると、CSS-in-JS ライブラリの JavaScript ランタイムは次の処理を行います。
- テンプレート文字列またはオブジェクト内の CSS を解析します。
- 一意のクラス名を生成します。
- ドキュメントの
<head>内にある<style>タグへスタイルを動的に挿入します。
この処理は JavaScript バンドルのサイズを増やし、アプリケーションの起動とレンダリング時に計算コストを加えるため、パフォーマンスに影響します。
2. 「ゼロランタイム」による打開策
実行時パフォーマンスの問題を解決するため、コミュニティは ゼロランタイム(Zero-Runtime)CSS-in-JS という新しい考え方を提案しました。
核となる考え方は、CSS-in-JS の開発体験を残しながら、すべての処理を ビルド時(build time) に完了させることです。通常は Babel プラグインや Vite プラグインであるビルドツールがコードを走査し、CSS-in-JS の使用箇所をすべて見つけて、次の処理を行います。
- CSS テキストを抽出します。
- 静的な
.cssファイルを生成します。 - 元の CSS-in-JS コードを、生成された一意のクラス名に置き換えます。
最終的にブラウザへ渡される JavaScript バンドルには CSS-in-JS のランタイムライブラリが一切含まれず、高度に最適化された静的 CSS ファイルを手書きした場合と同じ結果になります。
3. 主なゼロランタイムソリューション
a. Linaria
Linaria はゼロランタイム分野の先駆者の一つです。使い慣れた styled タグ付きテンプレートリテラル構文を使用できます。
// YourComponent.js
import { styled } from '@linaria/react';
const Title = styled.h1`
font-size: 2rem;
color: tomato;
`;
// 构建时,这会被转换为:
// <h1 class="Title_a1b2c3d">...</h1>
//
// 并在一个静态 .css 文件中生成:
// .Title_a1b2c3d {
// font-size: 2rem;
// color: tomato;
// }b. vanilla-extract
SEEK 社のチームが開発した vanilla-extract はさらに一歩進み、TypeScript を利用して完全に型安全なスタイルを作成します。すべてのスタイル定義は .css.ts ファイルからエクスポートされる変数であり、強力な型推論と自動補完を提供します。
// styles.css.ts
import { style } from '@vanilla-extract/css';
export const title = style({
fontSize: '2rem',
color: 'tomato',
});c. Panda CSS
Panda CSS は比較的新しい競合です。Tailwind CSS の考え方を取り入れ、「Style Props」による開発体験を提供しながら、ゼロランタイムの出力を保証します。
import { css } from '../styled-system/css';
function MyComponent() {
return <div className={css({ fontSize: '2rem', color: 'tomato' })} />;
}4. 利点とトレードオフ
利点:
- 最高のパフォーマンス: 最終成果物は静的 CSS であり、JavaScript ランタイムのコストがありません。
- 小さなバンドルサイズ: クライアントで CSS-in-JS ライブラリを読み込む必要がありません。
- 優れた開発体験: コンポーネントスコープ、TypeScript の型安全性、コードの同居という利点を引き続き得られます。
トレードオフ:
- ビルド時の依存: ビルド工程へ統合する必要があり、設定はやや複雑になります。
- 動的処理の制限: API から得たデータなど、実行時にしか分からない値に基づいてまったく新しいスタイルを生成することはできません。ただし、CSS 変数などの技術でほとんどの動的な場面を補えます。
結論
ゼロランタイム CSS-in-JS は、従来の CSS-in-JS パラダイムを正しい方向へ戻す試みです。「開発時の体験」と「実行時のパフォーマンス」を巧みに分離し、両者の間で難しい妥協をする必要をなくします。最高のパフォーマンスと小さなバンドルサイズを求めるモダン Web アプリケーションにとって、ほぼ完璧なソリューションを提供します。