コードの違いを比較！emotionとstyled-componentsの両方を使ってみた

# この記事はこんな人にオススメ
* React で CSS in JS の導入に当たって、emotion と styled-components のどちらを使おうかと悩んだので、両方をお試ししてみました。今回はお試しした比較・コードをまとめた記事です。
* CSS in JS 使ってみたいけどどんな書き方するのかわからないな〜っていう人はこちらを読んでなんとなく書き方を把握してもらえると嬉しいです！

## 今回のお試しコードについて
* 本記事はあくまで CSS in JS（emotion / styled-components）のみにフォーカスした記事です。
  * className を使った通常の css でのスタイリングをしない理由は、スタイリングのスコープが可能、変数や関数といった JavaScript のロジックが使用できるというメリットがあるためです。
* **今回はスタイリングの書き方比較のみをまとめたので、React の導入、import、export などは省略しています。**
* 下記で紹介しているコードはこちらにあります
  * [emition のサンプルコード](https://codesandbox.io/s/emotiontest-h7yp3?file=/src/App_emotion.js)
  * [styled-components のサンプルコード](https://codesandbox.io/s/styledcomponentstest-equ53)

# 使ってみた結論
* 今のところ styled-components より emotion がよさそう！
  * CSS Props が便利！
  * styled-components の機能もほぼ使える
* 以下にそれぞれのメリット・デメリットとコード例を紹介していきます。


## emotion
### メリット
* 何より CSS Props が便利！（追加の import いらずで使用可能）
* 様々な機能を import なしで利用可能（CSS Props, media Query など）
* emotion/styled を import すると、styled-components の一部機能が使える

### デメリット
* styled-components と比較して利用者数が少なく、記事なども少ない


## styled-compoents
### メリット
* おそらく一番使われている CSS in JS のライブラリで、情報量が多い
    * 2020/5/5 現在、styled-components のスター数：29.2k、emotion のスター数：10.7k
    * [npm trend（@emotion/core vs styled-components）](https://www.npmtrends.com/styled-components-vs-@emotion/core)

### デメリット
* スタイリングを目的とした要素を用意する必要がある
    * スタイルは使い回しでタグの要素だけ変更したい場合も、都度新しい要素を作成することになる
* 要素の宣言がスタイル側にあるため、DOM構造が視覚的に分かりにくい
  button、p などの要素指定がスタイル側に記述される


# emotion でのスタイリング
* インライン記法もできますが、業務ではなかなか使う機会がないため割愛します。
* 上記メリットにも記載しましたが、styled-components でのスタイリングも可能です。


## CSS Props
※分かりやすくするために、以下のコードは React のコードの、レンダリング層とスタイリング層のみ記載しています。

### CSS Props（オブジェクト記法）
* `css={hoge}`で class 名の指定が可能です。
* プロパティの書き方が従来の CSS とは少し違う書き方になります。

```cssProps.jsx
return (
    <p css={base}>CSS Props（オブジェクト記法）</p>
);

const base = css({
  backgroundColor: "#eee",
  fontSize: "20px",
  padding: "15px"
});

```

表示結果
<img width="546" alt="スクリーンショット 2020-03-08 19.41.42.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164666/ba174380-c816-ac1e-b868-c42be976d860.png">


### CSS Props（タグ付きテンプレートリテラル）
* こちらはプロパティの書き方が従来の CSS と同様の書き方になり、とっつきやすい記法です。
* emotion で一番ベーシックな書き方になります。

```tagliteral.jsx
return (
    <p css={tagliteral}>CSS Props（タグ付きテンプレートリテラル）</p>
);

const tagliteral = css`
  background-color: #ffc0cb;
  font-size: 20px;
  padding: 15px;
`;
```

表示結果
<img width="547" alt="スクリーンショット 2020-03-08 19.44.49.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164666/121c0204-9b30-1e9f-41af-d4bbcb866dd2.png">


## Composition（extend）
* Composition を使うことで、css で言うところの extend をすることが可能です。
* 今回は上記に記載した base のスタイルを読み込んでいます。

### オブジェクト記法 Composition（extend）
* プロパティの書き方が従来の CSS とは少し違う書き方の継承法です。

```tagcomposition.jsx
return (
    <p css={objectcomposition}>Composition（オブジェクト記法）</p>
);

const objectcomposition = css(base, {
  color: "#db7093"
});
```

表示結果
<img width="544" alt="スクリーンショット 2020-05-06 13.18.19.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164666/82501242-aea0-6522-1ac9-ba10b1417675.png">


### タグ付きテンプレートリテラルでの Composition（extend）
* プロパティの書き方が従来の CSS と同様の書き方の継承法です。
* sass の extend とも見た目が近いですね。

```tagcomposition.jsx
return (
  <p css={tagcomposition}>Composition（タグ付きテンプレートリテラル）</p>
);

const tagcomposition = css`
  ${base};
  font-weight: bold;
`;
```

表示結果
<img width="545" alt="スクリーンショット 2020-05-06 13.18.45.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164666/a77ad97d-c766-59e3-4cd9-a5a75ad59aa1.png">


## 並列 class
* 複数のスタイル設定を同時に指定することも可能です。

```parallel.jsx
return (
  <p css={[base, parallel]}>並列 class</p>
);

const parallel = css`
  border: solid #4682b4 2px;
`;
```

表示結果
<img width="545" alt="スクリーンショット 2020-05-06 12.53.05.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164666/0be6bcfa-0ae6-1997-b996-58a65775b887.png">


## ネスト（入れ子）
* sass のようにネストすることができます。
* ただ、後からコンポーネント分割するときに分割しずらくなることがあり、あまりオススメはしません。

```nest.jsx
return (
  <p css={nest}>
  <span>ネスト</span>記法
  </p>
);

const nest = css`
  background-color: #b0c4de;
  font-size: 20px;
  padding: 10px;
  span {
    background-color: #4682b4;
    padding: 5px;
  }
`;
```

表示結果
<img width="544" alt="スクリーンショット 2020-03-08 18.57.57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164666/0488e496-406b-d752-cabd-1e933bb758c4.png">



## グローバル
* Groba を import した上で使用します<br>
  `import { Global, css, jsx } from "emotion/core";`

```grobal.jsx
return (
  <Global styles={globalStyle} />
);

const globalStyle = css`
  html {
    background-color: #008b8b;
  }
`;
```

## style宣言のコードをまとめる
* class 毎に毎回 const で宣言するのではなく、ひとまとめにして固まり毎に記載することができます。

```styles.jsx
return (
  <p css={[styles.basetext, styles.boldtext]}>CSS 宣言をひとまとめに</p>
);
const styles = {
  basetext: css`
    background-color: #eee;
    font-size: 20px;
    padding: 15px;
  `,
  boldtext: css`
    font-weight: bold;
  `
};
```

表示結果
<img width="545" alt="スクリーンショット 2020-05-06 13.01.23.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164666/17a26449-cd47-0787-9fc7-53455c6ca152.png">




# styled-components でのスタイリング

## 基本系
* DOM 要素の宣言は`p`や`div`などではなく、任意で作成した名前を宣言します。
* スタイル設定時に DOM 要素を設定します。

```base.jsx
return (
  <BaseText>基本のスタイリング</BaseText>
)

const BaseText = styled.p`
  background-color: #eee;
  font-size: 20px;
  padding: 15px;
`;
```

表示結果
<img width="546" alt="スクリーンショット 2020-05-06 0.22.16.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164666/4c7d2841-068e-70c3-b254-9d85b7134642.png">


## extend
* emotion の オブジェクト記法での Composition に近い書き方になりますが、こちらは CSS プロパティが従来と同様の書き方になります。

```extend.jsx
return (
  <ExtendText>extend</ExtendText>
)

const ExtendText = styled(BaseText)`
  font-weight: bold;
`;
```

表示結果
<img width="546" alt="スクリーンショット 2020-05-06 12.34.54.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164666/bac5b8cd-6a4b-e676-1312-8e49afdb7325.png">


## ネスト（入れ子）
* sass と同様の書き方で記載が可能です。

```nest.jsx
return (
  <NestText>
    <span>ネスト</span>記法
  </NestText>
)

const NestText = styled.p`
  background-color: #b0c4de;
  font-size: 20px;
  padding: 10px;
  span {
    background-color: #4682b4;
    padding: 5px;
  }
`;
```

表示結果
<img width="545" alt="スクリーンショット 2020-05-06 12.35.17.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164666/a6371d55-676f-aaee-c57c-7057b4951602.png">


## グローバル
* styled-components の v4 から GrobalStyle が使用可能です。<br>
  [詳細はこちら](https://styled-components.com/docs/api#createglobalstyle)

```grobal.jsx
return (
  <GlobalStyle />
)

const GlobalStyle = createGlobalStyle`
  html {
    background-color: #008b8b;
  }
`;
```


## CSS Props
* styled-components の v4 から CSS Props が使用可能です。<br>
  [詳細はこちら](https://styled-components.com/docs/api#css-prop)
* 2020/5/5 現時点で、emotion の CSS Props のように、class 名のような形での機能はありません。

```cssprops.jsx
return (
  <p
    css={`
      background-color: #ffc0cb;
      font-size: 20px;
      padding: 15px;
    `}
  >
    CSS Props
  </p>
)
```

表示結果
<img width="547" alt="スクリーンショット 2020-05-06 12.35.25.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164666/745a0ed3-e505-f13e-daf7-c2a662ccf9ac.png">


# 最後に
* 書き方は色々あれども、結構通常の CSS の書き方に近いので、最初の導入ハードルを超えてしまえば運用自体はなんとかなりそうですね。
* styled-components で emotion のような CSS Props（class名を指定する形）が実現すると一番いいなぁと思います。これからのバージョンアップに期待…！