Emotionのコーディングルール考えてみた

## はじめに
社内のプロジェクトでCSSinJSライブラ入りとして[emotion](https://emotion.sh/docs/introduction)を導入したのでコーディングルールを考えてみました。

#### プロジェクトで使用する技術

| 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`関数が使えることが大きいです。

```tsx
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 を採用した話](https://techlife.cookpad.com/entry/2021/03/15/090000)


## css関数で作ったスタイルの変数名にプレフィックスとして「css」を付ける

変数のプレフィックスを統一することで、一目でスタイルを表す変数であると認識しやすくなります。
プレフィックスには`style`や`css`などいくつか候補あると思いますが、文字数が短くcssプロパティともイメージづけしやすい`css`をプレフィックスとしてつけると良いと考えます。
また、エディタの補完機能が働き、cssと入力した時点で作成したスタイルの一覧が入力候補として表示されるようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453689/b3fa71e1-e864-9407-f45a-42c9b4529bc5.png)

```tsx:実装例
const Button = ({children}) => {
  return <button css={cssButton}>{ children }</button>
}

const cssButton = css`
  background: #ddd;
  border-radius: 30px;
`;
```

### Highlightの設定
その他にVSCodeの拡張機能「[Highlight](https://marketplace.visualstudio.com/items?itemName=fabiospampinato.vscode-highlight)」を使って、cssから始まる文字の色を変更することで、変数がcss関数で作られたスタイルを意味するのかそれ以外なのか区別しやすくできます。


拡張機能をインストールして、VSCodeの設定ファイルに以下の設定を追加する。
colorは自由に変更してください。


```json:settings.json
    "highlight.regexes": {
        "(css[a-zA-Z0-9_]+)": {
            "filterFileRegex": ".*(jsx|tsx)$",
            "decorations": [
                {
                    "color": "OldLace",
                }
            ]
        },
    }
````

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453689/b2a3176d-e245-63bc-a508-418e72572e75.png)


## 親コンポーネントからcssを渡したいときは、子コンポーネント側はclassNameで受け取り、cssプロパティの後ろにclassNameを設定する
emotionを使用すると、`css`プロパティで渡したスタイルは内部で`className`という`props`に変換されて子コンポーネントに渡されます。（参考記事：[Emotionを使いこなす](https://qiita.com/282Haniwa/items/7248bed02a1b5b66579f)）
そのため、親から子へスタイルを渡した場合は、子コンポーネントは`css`プロパティと`className`プロパティの両方を扱う必要があります。

この二つを同時に指定した場合、`className`プロパティで渡したスタイルの優先度が高くなるのですが、どちらのプロパティを先に記述した方が可読性が高いか考えるときに`css`プロパティ内でのマージ方法を参考にします。

`css`プロパティ上でスタイルをマージする方法として、配列で`css={[style1, style2]}`と記述する方法があります。
この場合、配列の後ろに格納した`style2`の優先順位が高くなります。

このルールに基づき、`css`プロパティより優先度が高い`className`プロパティを後ろに書くことで優先順位をイメージしやすくなります。

```tsx:記述例
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;
`;
```
このように指定すると、以下のようにスタイルが定義されます。![スクリーンショット 2021-09-20 16.56.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453689/d88214ab-06a4-ea9c-84da-d7b5d193b4a0.png)

## おわり
今回のプロジェクトは走り出したばっかりなので今後ルールは増えてくると思いますが、最初に決めておくルールはこれぐらいかなと思います。
またルールが増えたり変更することがあれば都度、追記していきたいと思います。