Vueで使えるCSS in JSを調べてみた


この記事はAteam Brides Inc. Advent Calendar 2019 20日目の記事です。

本日はWebデザイナーの@naomunaomuが担当いたします。
2回目の登場です☺️

## 背景
VueのScoped CSSは非常に便利だと思うのですが、スタイルがバッティングするなどの懸念点もあり、結局BEMから抜け出せない感じがなんだかなあ・・と思っていたり。

参考
[Vue.jsのscoped CSSは意外とバッティングする - Qiita](https://qiita.com/wintyo/items/dfc232255ad45fdf376f)

「CSSのグローバルスコープ問題を解決し、脱BEMしたい・・」

その銀の弾丸としてCSS in JSがあるのではないか。と淡い期待を込めて調べてみたところ、Vueの場合、Scoped CSSやUIフレームワークのおかげで、CSS in JSの参考例が少なく困ってしまいました・・　

Reactを先に学んだ自分は、「Reactのstyled-componentsってVueでも使えるの？」「Scss以外の選択肢を知っておきたい」と単純に気になったんですよね

というわけで紹介していきます！

## そもそもCSS in JSってなに
その名の通り、JSをつかってスタイルを表現することが可能です。

よく勘違いされますが、インラインで展開されるスタイルとは別物です。
CSS in JSは`<style>`がDOMのTOPに表示されますし、
インラインでは使えない、`:before`などの擬似要素も使えます。
そして、CSSにローカルスコープが付与できるんです。*ひゃっほー！*🎉

## styled-compornent
[GitHub - styled-components/vue-styled-components: Visual primitives for the component age. A simple port for Vue of styled-components 💅](https://github.com/styled-components/vue-styled-components)

Reactで使われてる方が多いかと思いますが、実はvueにもあります
JSで受け取ったpropsの値でCSSに当てられるところが最高です！

Vue<=>Reactを行き来させる予定のある場合、統一した書き方ができるところもGoodですね

```
<styled-button>Normal</styled-button>
<styled-button primary>Primary</styled-button>
```

タグ付きテンプレートリテラルを使用し、JS内にCSSを書きます。

```vue
<script>
import styled from 'vue-styled-components';

const btnProps = { primary: Boolean };

//scriptタグの中にスタイルを書きます
const StyledButton = styled('button', btnProps)`
  font-size: 1em;
  margin: 1em;
  padding: 0.25em 1em;
  border: 2px solid palevioletred;
  border-radius: 3px;
  background: ${props => props.primary ? 'palevioletred' : 'white'};
  color: ${props => props.primary ? 'white' : 'palevioletred'};
`;

export default StyledButton;
</script>
```

[GitHub - styled-components/vue-styled-components: Visual primitives for the component age. A simple port for Vue of styled-components 💅](https://github.com/styled-components/vue-styled-components)

JSでCSS書いてますが、最終的にはちゃんとCSSで吐き出されるので、従来通りCSS設計の考え方、定数管理は必要です。

## vue-emotion
[GitHub - egoist/vue-emotion: Seamlessly use emotion (CSS-in-JS) with Vue.js](https://github.com/egoist/vue-emotion)
こちらもReactユーザーには馴染みがあるのではないでしょうか。
後発のライブラリな分、CSS in JSでできることはだいたいできるとのこと。

styled-compornent同様、JSでCSS書いてます。


[CSS-in-JSのライブラリとして「emotion」を選択している理由 - Qiita](https://qiita.com/__sakito__/items/d240840eef7123f62acf)

実行速度・ファイルサイズを比べると、styled-compornentよりemotionの方がよさそうですが、ちょっと情報が少ないですね・・ドキュメントを読んだところ、vue-emotionではcss PropやObject Stylesなどは使えなそう・・
styled-compornentでよさそうです。


## CSS Modules
Scoped CSSを使っている方は一番馴染み深い書き方かもしれません。
Scoped CSSがカスタムデータ属性`data-hogehoge`を付与することで、元のclass名に影響を与えないことに対し、
CSS Modulesの場合、`コンポーネント名_class名_ランダムな値`となり、class名自体が変わることで、css名のバッティングを防ぎます。

`<style>`タグにscopeの代わりに、module属性を記述できます。

```vue
//公式ドキュメントより抜粋
<style lang='scss' module>
.blue {
  color: blue;
}
</style>
```

htmlの方はこんな感じで、`:class=$style.foo`で記述します。`:`がないとスタイルが反映されないので注意！

```vuejs
//公式ドキュメントより抜粋
<template lang="pug">
  p(:class="$style.blue" :id="$style.blue")
    This should be blue
</template>

```

通常のclassとも併用できます。utilityなど、グローバルなcssを当てるときはこちら。


```vue
//公式ドキュメントより抜粋
<template lang="pug">
  //- 複数スタイルの指定も可能
  p.red(:class="[$style.red, $style.bold]" :id="$style.blue")
    This should be blue
    
  p(:class="{ [$style.red]: isRed }" :id="$style.blue")
    This should be blue
</template>
```

通常のscopeとも併用できますが、そんなに併用するかわかりません・・

```vue
//公式ドキュメントより抜粋
<style lang='scss' module>
.blue {
  color: blue;
}
</style>
<style lang='scss' scope>
.red {
  color: red;
}
</style>
```
導入ハードルも低く個人的にはおすすめですが、やっぱりScoped CSSに比べると、コードの見通しが気になります😢
自分の場合VueはPugで書いているので、PugでシンプルにHTMLが書ける分、冗長さが際立ってしまうのが残念というか・・
この辺は好みですかね？

## 結論
以上3つをまとめた結果です。

・BEMを辞める、React<->Vueの行き来を考えるなら->styled-compornent
・Vue単体なら->CSS Modules
・別に不便ない->Scoped CSS

というところが良いかなと言う印象でした。
BEM使うからclassのバッティング懸念しない、という場合は引き続きScoped CSSで全く問題なさそうです。

個人的にはstyled-compornentが好きなので、Vueでも試してみようと思います🙇‍♀️

### おまけ：デザイナ的にどっちが使いやすいとかある？
正直**とくにありません。**
どのCSS in JSを使用しても、下記が考慮されれば問題ありませんし、だいたいどれでも実現できます。若干の書き方の違い、気持ち悪さは**慣れです**
- propsでによるスタイルの変更ができる
- グローバル変数が使える
  - Scssが使えなければ、CSSで対応可能

ただ、UIフレームワークでしか開発経験がないメンバーしかいない場合、保守性・汎用性を考慮したCSS設計を行えるデザイナと協業できるとよさそうです〜

# 私たちのチームで働きませんか？
![alt](https://brides.a-tm.co.jp/wp-content/uploads/2019/11/ATEAM_BRIDES.jpg)
[エイチーム](https://www.a-tm.co.jp/)は、インターネットを使った多様な技術を駆使し、幅広いビジネスの領域に挑戦し続ける**名古屋の総合IT企業**です。
そのグループ会社である**株式会社エイチームブライズ**では、一緒に働く仲間を募集しています！

- [ハナユメ サイト開発グループ](https://jobs.qiita.com/employers/brides-a-tm/development_teams/138)
- [HIMARI開発チーム](https://jobs.qiita.com/employers/brides-a-tm/development_teams/147)
- [技術開発部](https://jobs.qiita.com/employers/brides-a-tm/development_teams/148)

上記求人をご覧いただき、少しでも興味を持っていただけた方は、まずは**チャットでざっくばらんに話**をしましょう。
技術的な話だけでなく、私たちが大切にしていることや、お任せしたいお仕事についてなどを詳しくお伝えいたします！

[Qiita Jobs](https://jobs.qiita.com/)よりメッセージお待ちしております！