Emotion コーディングルール案
はじめに
社内のプロジェクトでCSSinJSライブラ入りとしてemotionを導入したのでコーディングルールを考えてみました。
プロジェクトで使用する技術
| package | version |
|---|---|
| next | v11.1.2 |
| typescript | v4.4.3 |
| @emotion/react | v11.4.1 |
css関数を使ってスタイルを定義する
emotionではstyle-componentと同様にスタイルを含むコンポーネントを作成するstyled関数と、コンポーネントと独立してスタイルを定義できるcss関数が用意されています。
css関数を使うことで従来のマークアップのようにHTMLとCSSを分別することができるので、css関数を使うことにします。
emotionを導入した理由もcss関数が使えることが大きいです。
import { css, styled } from '@emtion/react';
// styledを使った書き方
const StyleButton = styled.button`
width: 100px;
`;
const Button = ({ children }) => {
return <StyledButton>{ children }</styledButton>
}
// cssを使った書き方
const buttonStyle = css`
width: 100px;
`;
const Button = ({ children }) => {
return <button css={buttonCss}>{children}</button>
}
cssの記述はファイルの下段に定義する
一つのjsxファイルでコンポーネントのロジック、HTML、CSSを記述するので、それぞれの記述が混在すると可読性が落ちてしまいます。
VueのSFCの記述のように一番下にスタイルを記述することでどこに何が記載されているか予測しやくなります。
参考:レシピサービスのフロントエンドに CSS in JS を採用した話
css関数で作ったスタイルの変数名にプレフィックスとして「css」を付ける
変数のプレフィックスを統一することで、一目でスタイルを表す変数であると認識しやすくなります。
プレフィックスにはstyleやcssなどいくつか候補あると思いますが、文字数が短くcssプロパティともイメージづけしやすいcssをプレフィックスとしてつけると良いと考えます。
また、エディタの補完機能が働き、cssと入力した時点で作成したスタイルの一覧が入力候補として表示されるようになります。

const Button = ({children}) => {
return <button css={cssButton}>{ children }</button>
}
const cssButton = css`
background: #ddd;
border-radius: 30px;
`;
Highlightの設定
その他にVSCodeの拡張機能「Highlight」を使って、cssから始まる文字の色を変更することで、変数がcss関数で作られたスタイルを意味するのかそれ以外なのか区別しやすくできます。
拡張機能をインストールして、VSCodeの設定ファイルに以下の設定を追加する。 colorは自由に変更してください。
"highlight.regexes": {
"(css[a-zA-Z0-9_]+)": {
"filterFileRegex": ".*(jsx|tsx)$",
"decorations": [
{
"color": "OldLace",
}
]
},
}

親コンポーネントからcssを渡したいときは、子コンポーネント側はclassNameで受け取り、cssプロパティの後ろにclassNameを設定する
emotionを使用すると、cssプロパティで渡したスタイルは内部でclassNameというpropsに変換されて子コンポーネントに渡されます。(参考記事:Emotionを使いこなす)
そのため、親から子へスタイルを渡した場合は、子コンポーネントはcssプロパティとclassNameプロパティの両方を扱う必要があります。
この二つを同時に指定した場合、classNameプロパティで渡したスタイルの優先度が高くなるのですが、どちらのプロパティを先に記述した方が可読性が高いか考えるときにcssプロパティ内でのマージ方法を参考にします。
cssプロパティ上でスタイルをマージする方法として、配列でcss={[style1, style2]}と記述する方法があります。
この場合、配列の後ろに格納したstyle2の優先順位が高くなります。
このルールに基づき、cssプロパティより優先度が高いclassNameプロパティを後ろに書くことで優先順位をイメージしやすくなります。
const Parent = () => {
return <div>
<Child css={cssParentToChild} />
</div>
}
const Child: React.FC<{ className?: string}> = ({ className }) => {
return <div css={[cssChild1, cssChild2]} className={className}>child</div>
}
const cssParentToChild = css`
top: 3px;
`;
const cssChild1 = css`
top: 1px;
`;
const cssChild2 = css`
top: 2px;
`;
このように指定すると、以下のようにスタイルが定義されます。
