CSS in JSライブラリ「emotion」のすすめ
React/Nextでスタイリングをどうすればいいか最近ずっと考えていた(いる)のですが、だんだんまとまってきたので書いておこうと思います。
CSS ModuleからCSS in JSへ
自分はもともとCSS Modules(SASS)を使っていたのですが、アニメーションライブラリとの相性で不具合があった(後に解決したのですが)ことや、Atomic Designを導入するとファイル構造をどうすればいいのか迷いまくっていたことから、CSS in JSに乗り換えを検討する流れになりました。
一番困っていたのがファイル構造で、atomsに当たるような一番小さいコンポーネントにもcss/sassファイルを作らなければならないのが個人的にすごく嫌で、小さくコンポーネントを分離させるのに抵抗ができてしまうなぁと思っていました。
CSS in JSライブラリ選定
主な検討項目としては
- マークアップのタグ自体を変数にはしたくない(どれがピュアなhtmlかぱっと見でわかりづらくなるので)
- mixinやconfigなどは一つにまとめて、グローバルで使いまわせるようにしたい
- コンポーネント間で柔軟にスタイルの上書きなどができるようにしたい
- なるべくReact/Nextを使わないひとでも理解しやすいものにしたい
といったことを中心にライブラリ選定しました。
検討したのは、主に次の3つです。
- styled-components
- styled-jsx
- emotion
styled-componentsは、1が解決できなそうだったので×
styled-jsxは2が解決できなそうだったので×
ということで、emotionを使うことにしました。
emotionの良さ
コードはNext.jsを使ってる例です。
使い勝手
cssプロパティに@emotion/react
からインポートしたcssを返せばいいので、ピュアなhtmlのタグ名のままスタイルを適用することができます。
import { css } from '@emotion/react'
export const Hoge: React.FC = () => (
<div css={hoge}>
<p>hoge</p>
</div>
)
const hoge = css`
margin: 100px auto 0;
`
関数化して柔軟にスタイルの上書き等も行うことができます。(これが良いかは別として)
同じように、グローバルにメディアクエリなどのmixinの関数を置いておいて使いまわすこともできます。
import { css, SerializedStyles } from '@emotion/react'
type Props = {
text: string
_css?: SerializedStyles
}
const H1: React.FC<Props> = ({ text, _css }) => (
<h1 css={title(_css)}>{text}</h1>
)
const title = (_css: SerializedStyles): SerializedStyles => css`
position: relative;
font-size: 50px;
line-height: 1;
${_css}
`
パフォーマンス
styled-componentsよりも若干emotionのほうがパフォーマンスが良いようです。
参考:Styled components vs Emotion js: A performance perspective
今後のメンテナンス性(トレンド)
現在はstyled-componentsのほうがemotionよりも人気のようです。
参考:SassからCSS Modules、そしてstyled-componentsに乗り換えた話
運用を伴う大きなプロジェクトで使用するには今後のメンテンナンス性が大きく影響しますが、自分は広告制作会社勤務で運用なども発生する案件が少ないため、そこまで重要視しませんでした。
Discussion