
- はじめに
- 技術選定の背景
- 評価観点
- ランタイムとゼロランタイム、そしてハイブリッドCSS in JS という選択肢
- 比較結果
- パフォーマンス測定
- 🐻❄️Kuma UIについて
- Kuma UI導入にあたっての課題
- 最後に
⚠️この記事は、2023年11月20日時点の情報をもとに制作しています。
はじめに
この記事は、DMMグループAdvent Calendar 2023の4日目の寄稿です。
こんにちは!2023年に新卒として入社し、動画配信開発部でフロントエンドエンジニアをしている大坂 (@yud0uhu) といいます。
私は社内のとあるプロダクトの開発に関わる中で、CSSライブラリ選定のための技術調査を行うことになりました。
この記事では、ライブラリの技術選定を行うにあたり、検討した背景や観点、パフォーマンスを定量的に測定・比較した結果についてお話します。
技術選定の背景
私たちの関わるプロダクトでは、CSSライブラリにEmotionを採用していました。
EmotionをはじめとしたランタイムCSS in JSは、スタイルの生成のためブラウザ上でJavaScriptが実行されます。大規模なアプリケーションであるほど、スタイル描画によるオーバーヘッドが肥大化する懸念があります。
私たちが提供するサービスは、ユーザーが複数のデバイスから利用するユースケースが存在します。
ブラウザ側のランタイムオーバーヘッドやバンドルサイズの肥大化は、異なるデバイスでの利用において影響を及ぼす可能性があります。この課題に対処するため、選択した技術スタックが異なるデバイスで一貫性のあるパフォーマンスを提供できるよう検討を行う必要がありました。
評価観点
Emotionに代わる新しいCSS環境を検討するにあたり、私たちが重視したい項目は下記の三点でした。
- パフォーマンス
- 学習コスト
- Next.js(SSR)環境で問題なく使えること
先述の通り、パフォーマンスは最も重視すべき項目です。
学習コストは、書き心地とスピード、保守性・可読性の三点で定性的に評価を行います。
私たちのプロダクトでは、Next.jsの環境を十分に使うこと(SSR、RSC対応、App Routerの導入)に力を入れており、このような環境下で問題なく動くことも要件の一つでした。
しかし、ランタイム環境でJSの実行を必要とするCSS in JS は、2023/11/20時点でReact Server Components ではサポートされていません。
Warning: CSS-in-JS libraries which require runtime JavaScript are not currently supported in Server Components. Using CSS-in-JS with newer React features like Server Components and Streaming requires library authors to support the latest version of React, including concurrent rendering.
We're working with the React team on upstream APIs to handle CSS and JavaScript assets with support for React Server Components and streaming architecture.
また現状、App Routerに対応しているCSS in JS は以下とされています。
- kuma-ui
- @mui/material
- pandacss
- styled-jsx
- styled-components
- style9
- tamagui
- tss-react
- vanilla-extract
(https://nextjs.org/docs/app/building-your-application/styling/css-in-js より)
RSCで機能することやApp Routerへの移行も検討するのであれば、これらの制約も考慮する必要があります。
ランタイムとゼロランタイム、そしてハイブリッドCSS in JS という選択肢
今回、検討したのは大きく二つです。
- CSS Module
- CSS in JS
これらの比較を行う前に、CSS in JS の現状について考えてみます。
そもそもCSS in JS は、スタイル表現をJavaScriptのコード内に取り込むアプローチです。これによって、外部のCSSファイルに依存することなく、コンポーネント単位でスタイルを管理し、JavaScriptの機能を使った動的なスタイリングを行うことができます。
EmotionのようなCSS in JS ライブラリは、独自のキャッシュ機構を使いながら効率的にJavaScriptで作成したCSSオブジェクトをプレーンCSSに変換(シリアライズ)し、<style /> タグに挿入することで、動的なスタイリングを可能にしています。
しかし、コンポーネントのレンダリングの度にランタイムでスタイルの再計算が行われるため、パフォーマンスのオーバーヘッドの発生は避けられません。
Reactの公式ドキュメントでも、ランタイム環境における <style /> タグの挿入を二つの理由から非推奨としています。
- Runtime injection forces the browser to recalculate the styles a lot more often.
- Runtime injection can be very slow if it happens at the wrong time in the React lifecycle.
ここで昨今では、ランタイムオーバーヘッドのないCSS in JS というコンセプトの、ゼロランタイムCSS in JS が登場しました。
ゼロランタイムCSS in JS は、スタイルをビルドプロセス中に抽出し、CSSに変換することで、このようなコンセプトを実現しています。
さらに、ビルド時の静的解析とレンダリング時の動的実行の両立を実現したCSS in JSも登場しました。Kuma UI や Panda CSS などのCSS in JS ライブラリは、ランタイムCSS in JS の持つスタイリングの表現力と、ゼロランタイムCSS in JS によるパフォーマンス上の利点を兼ね合わせたハイブリッドなアプローチを行えることが特徴です。
| CSS in JS | 仕組み | ライブラリ |
|---|---|---|
| ゼロランタイム | ビルド時の静的解析でCSSの抽出を行う | Linaria、Stitches |
| ハイブリッド | 基本的にビルド時の静的解析でCSSの抽出を行い、動的なスタイルはランタイムで処理を行う | Kuma UI、Panda CSS |
| ランタイム | 動的なスタイルを処理できるが、実行時にCSSの抽出を行うため、ランタイムオーバーヘッドが発生する | Emotion、styled-components |
比較結果
最終的に、以下のライブラリを選定の候補としました。
- Kuma UI
- Panda CSS
- Linaria
- CSS Modules
Kuma UIとPanda CSS は比較的新しいライブラリということもあり、GitHub上のシェア数はLinaria が圧倒的です。
比較のため、実際にこれらのCSS in JSとCSS Modules を用いてこのようなサンプルボタンを作成しました。

ライブラリごとの実装の違いについては、リファレンスコードとREADMEを下記リポジトリにまとめています。
- https://github.com/yud0uhu/basic-kuma-ui-app
- https://github.com/yud0uhu/basic-panda-app
- https://github.com/yud0uhu/basic-linaria-app
- https://github.com/yud0uhu/basic-css-modules-app
ライブラリごとの比較表
| 比較項目 | Emotion | CSS Modules | Kuma UI | Linaria | Panda CSS |
|---|---|---|---|---|---|
| ゼロランタイム(CSS in JSのみ) | (ランタイム) | ✓ (ハイブリッド) | ✓ (ゼロランタイム) | ✓ (ハイブリッド) | |
| SSR対応 | ✓ https://emotion.sh/docs/ssr | ✓ | ✓ https://www.kuma-ui.com/docs/install#server-side-rendering | ✓ https://github.com/callstack/linaria/blob/master/docs/API.md#server-apis-linariaserver | ✓ https://panda-css.com/docs/migration/stitches#server-side-rendering https://panda-css.com/docs/migration/styled-components#server-side-rendering |
| コンポーネントと同じファイルに書ける | ✓ | (.module.cssに書く必要がある) | ✓ | ✓ | ✓ |
| CSSの記述方法 | String Styles、Object Styles | Object Styles、String Styles | Object Styles、String Styles | Object Styles、String Styles | |
| RSC対応 | ✓ | ✓ | ✓ | ✓ | ✓ |
| App Router対応 | なし | ✓ | ✓ | ✓ | ✓ |
| Stylelint | ✓ https://www.npmjs.com/package/@stylelint/postcss-css-in-js (deprecated) | ✓ https://www.npmjs.com/package/stylelint-config-css-modules | ✓ https://www.kuma-ui.com/docs/Recepies/Linting | ✓ https://github.com/callstack/linaria/blob/master/docs/LINTING.md | なし |
| Storybook対応 | ✓ | ✓ | ✓ | ✓ | ✓ |
ここまで比較した結果、学習コスト面では特にKuma UIに魅力を感じました。
- 既存プロダクトへの導入(環境構築)が最も簡単だった
- css APIやstyled API を使えば、Emotion のような書き心地で書けること
- 移行段階で仮に変更することになっても、上記二つの理由から、環境の変更や巻き戻しが最小限で行えそうなこと
- css API やstyled API はランタイム環境で使えないという制約はあるものの、Utility Props を使えば動的なスタイルの切り替えも行えること
パフォーマンス測定
パフォーマンスの比較のため、コンポーネントのレンダリングのベンチマーク測定を行いました。

https://github.com/yud0uhu/css-optimization-benchmarks
各ライブラリの導入環境下で、5000枚のダミーイメージをレンダリングするコンポーネントを作成し、どの程度の時間を要しているかをプロファイリング結果から分析・評価を行いました。
計測環境
| ブラウザの種類 | バージョン | OS | CPU | メモリ |
|---|---|---|---|---|
| Google Chrome | 119.0.6045.159(Official Build) (arm64) | macOS | Apple M2 | 16GB |
ここでは、styled-components やStitches などのCSS in JS についても測定を行なっています。
計測結果
| 計測対象 ライブラリ名 |
レンダリング時間 | ||
|---|---|---|---|
| 1フレーム目 | 2フレーム目 | 3フレーム目 | |
| kuma UI (css api+Utility Props) | 60.4ms | 56.7ms | 52.4ms |
| CSS Modules | 86.2ms | 77ms | 75.8ms |
| Linaria CSS | 97.4ms | 86.4ms | 81.5ms |
| Stitches | 109.9ms | 99.2ms | 94.5ms |
| Panda CSS | 120.9ms | 114.3ms | 115.9ms |
| kuma UI (styled api+Utility Props) | 191.1ms | 177.2ms | 185.2ms |
| Emotion | 324.4ms | 301.1ms | 292.7ms |
| styled-components | 378ms | 192.5ms | 156.1ms |
これらの総合的な結果を踏まえて、私たちはEmotionから「Kuma UI」への移行を検討するフェーズにいます。
🐻❄️Kuma UIについて
Kuma UI は、ヘッドレスなUIコンポーネント集とゼロランタイムで動くCSS in JS を兼ねたライブラリです。
ビルド時に決定できるスタイルを静的に抽出し、動的に変更される可能性のあるスタイルに対しては実行時にDirty Checking を行なうことで、ハイブリッドなアプローチを実現しているようです。
ヘッドレスUIコンポーネントも兼ねていることから、独自のデザイントークンを自由に組み合わせることもできます。
Kuma UI is standing on the shoulders of giants. We've drawn inspiration from some of the most innovative libraries in the CSS-in-JS ecosystem.
- Styled System(opens in a new tab): The concept of system props in Kuma UI is heavily inspired by Styled System.
- Chakra UI(opens in a new tab): From Chakra UI, we've learned the power of simplicity and intuitive API design.
- Native Base(opens in a new tab): Native Base's philosophy of a completely customizable and themeable library aligns with our own.
- Panda CSS(opens in a new tab): The simplicity and directness of Panda CSS have influenced our approach to Hybrid CSS-in-JS.
- Linaria(opens in a new tab): The static extraction concept in Kuma UI is inspired by Linaria.
- Vanilla Extract(opens in a new tab): From Vanilla Extract, we learned about the possibility of theming and zero-runtime CSS in TypeScript.
Each of these libraries brought something unique to the table, and we've incorporated their best features into Kuma UI. It's our way of saying "thank you" to these incredible open-source projects, and our way of giving back to the community.
Chakra UIをはじめ、従来のUIコンポーネントライブラリやCSS in JS の利点を取り入れていることが紹介されています。
メンテナの𝗉𝗈𝗍𝖾𝖻𝗈𝗒 さんによる紹介記事はこちらです。
Kuma UI導入にあたっての課題
Kuma UI のcss APIを使用すると、Emotionのようにタグ付きテンプレートリテラルを使用したスタイルの定義を行うことができます。
Emotion で書かれたコンポーネントをKuma UI に移行するにあたり、いくつかの課題がありました。
例えば、カルーセルのスクロールバーは以下の擬似要素で制御していました。
&::-webkit-scrollbar": { display: 'none' }
これをKuma UIで扱うには、css APIを使って下記のように書く必要があります。
const buttonStyle = css`
&::-webkit-scrollbar {
display: "none";
}
`;
しかし、このようなビルド時の静的解析で評価できないものについては、css APIでは現状サポートされていません。
Please note that the css API does not currently support interpolations in the same way as libraries like Emotion does. However, we are actively working to incorporate this feature, so stay tuned for updates.
ランタイム環境下での動的なスタイル処理を伴うものは、Kuma独自のUtility Props で補う必要があります。
Utility Props の記法は、現状いくつかサポートされていないCSSプロパティがあり、webkit-scrollbarはサポートされていません。
このように、サポート外のCSSプロパティを乗り換え時にどう扱うか?を検討する必要があります。
こういった一部プロパティについては、公式のサポートを待ちつつ、素のCSSやSassと組み合わせて開発を行う方針が一つの解決案として考えられそうです。
最後に
Webフロントエンドは技術トレンドの移り変わりが激しく、ライブラリやフレームワークの選定に一つの正解はありません。
組織やアプリケーションが抱える課題を洗い出した上で、合意形成に必要なリファレンスを集めたり、必要な場面で意思決定を行うことで、このような課題に向き合っていければと思います。