背景
新規で CSS in JS を利用するにあたり、Emotionを選定した。
個人的に選定理由をまとめておきたいので簡潔に書いていく。
CSS in JS のライブラリとして必要とした機能は以下。
font-size
→ fontSize
)選定条件としては以下。
パフォーマンスの観点で Zero-runtime CSS in JS ライブラリも選択肢のひとつとして挙がった。
API が styled-components や Emotion などの先発ライブラリと同様の構文を有しているlinariaを確認してみた。
小規模なアプリケーションの場合は良さそうだが、以下の点で linaria は見送った。
動的なスタイルを多用した場合に CSS Custom Properties の出力が多くなり、HTML が肥大化してしまう
動的なスタイルの値がundefined
な場合に不要なプロパティが残る
const Heading = styled.h1`
background-color: ${({ bg }) => bg};
`;
const Example = () => {
return (
<>
<Heading bg="red">Red Heading</Heading>
<Heading>Heading</Heading>
</>
);
};
↓
<h1 class="t1vg9j5w" style="--t1vg9j5w-0:red;">Red Heading</h1>
<h1 class="t1vg9j5w" style="--t1vg9j5w-0:undefined;">Heading</h1>
<style>
.t1vg9j5w {
background-color: var(--t1vg9j5w-0);
}
</style>
値がundefined
の場合でもプロパティが残る
同じコンポーネントをネストすると再利用された CSS Custom Properties が上書きされていまい意図した動作をしない
const Stack = styled.div`
& > * + * {
margin-top: ${({ spacing }) => spacing || "0"};
}
`;
const Example = () => {
return (
<Stack spacing="1rem">
<Stack></Stack>
<Stack></Stack> {/* 👈 */}
</Stack>
);
};
ネストされた 2 番目のStack
のmargin-top
は1rem
となることを期待するが、CSS Custom Properties の上書きによって0
になってしまう
採用事例・ドキュメントが少ない
検討結果、候補は styled-components もしくは Emotion の 2 つになった。
ライブラリ | タグ付きテンプレート | オブジェクトスタイル | グローバルスタイル | ネストセレクタ | TypeScript サポート | Server Side Rendering |
---|---|---|---|---|---|---|
styled-components | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
Emotion | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
npm パッケージのダウンロード数だけで見ると emotion が styled-components よりも多くなっている(emotion はパッケージが分かれているため単純比較は難しい)。
ちなみに GitHub のスター数は styled-components の方が多い。
next build
の結果比較Next.js 上で styled-components と Emotion のそれぞれを利用した場合のビルド結果を比較した。
ビルド後のファイルサイズを比較すると Emotion の方がファイルサイズは小さいようだった。
対象パッケージは以下の通り。
next build
の実行結果は以下の通り。
Page Size First Load JS
┌ ○ / 3.27 kB 90.6 kB
├ /_app 0 B 87.3 kB
├ ○ /404 2.67 kB 90 kB
└ ○ /other 1.06 kB 88.4 kB
+ First Load JS shared by all 87.3 kB
├ chunks/framework-5f4595e5518b5600.js 42 kB
├ chunks/main-13980ce3a4ae3dcf.js 29 kB
├ chunks/pages/_app-5392701c868a5bd6.js 14.7 kB
└ chunks/webpack-7b5c3cf34b918637.js 1.58 kB
https://github.com/hiro0218/css-in-js-analysis/tree/styled-components
対象パッケージは以下の通り。
next build
の実行結果は以下の通り。
Page Size First Load JS
┌ ○ / 3.21 kB 84.1 kB
├ /_app 0 B 80.8 kB
├ ○ /404 2.67 kB 83.5 kB
└ ○ /other 1.06 kB 81.9 kB
+ First Load JS shared by all 80.8 kB
├ chunks/framework-5f4595e5518b5600.js 42 kB
├ chunks/main-13980ce3a4ae3dcf.js 29 kB
├ chunks/pages/_app-0710a7201ba41fb0.js 8.07 kB
└ chunks/webpack-3bd2f374eaae16d4.js 1.71 kB
https://github.com/hiro0218/css-in-js-analysis/tree/emotion