この記事はAteam Brides Inc. Advent Calendar 2019 20日目の記事です。
本日はWebデザイナーの@naomunaomuが担当いたします。
2回目の登場です☺️
背景
VueのScoped CSSは非常に便利だと思うのですが、スタイルがバッティングするなどの懸念点もあり、結局BEMから抜け出せない感じがなんだかなあ・・と思っていたり。
参考
Vue.jsのscoped CSSは意外とバッティングする - Qiita
「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
Reactで使われてる方が多いかと思いますが、実はvueにもあります
JSで受け取ったpropsの値でCSSに当てられるところが最高です!
Vue<=>Reactを行き来させる予定のある場合、統一した書き方ができるところもGoodですね
<styled-button>Normal</styled-button>
<styled-button primary>Primary</styled-button>
タグ付きテンプレートリテラルを使用し、JS内にCSSを書きます。
<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>
JSでCSS書いてますが、最終的にはちゃんとCSSで吐き出されるので、従来通りCSS設計の考え方、定数管理は必要です。
vue-emotion
GitHub - egoist/vue-emotion: Seamlessly use emotion (CSS-in-JS) with Vue.js
こちらもReactユーザーには馴染みがあるのではないでしょうか。
後発のライブラリな分、CSS in JSでできることはだいたいできるとのこと。
styled-compornent同様、JSでCSS書いてます。
CSS-in-JSのライブラリとして「emotion」を選択している理由 - Qiita
実行速度・ファイルサイズを比べると、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属性を記述できます。
//公式ドキュメントより抜粋
<style lang='scss' module>
.blue {
color: blue;
}
</style>
htmlの方はこんな感じで、:class=$style.foo
で記述します。:
がないとスタイルが反映されないので注意!
//公式ドキュメントより抜粋
<template lang="pug">
p(:class="$style.blue" :id="$style.blue")
This should be blue
</template>
通常のclassとも併用できます。utilityなど、グローバルなcssを当てるときはこちら。
//公式ドキュメントより抜粋
<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とも併用できますが、そんなに併用するかわかりません・・
//公式ドキュメントより抜粋
<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設計を行えるデザイナと協業できるとよさそうです〜
私たちのチームで働きませんか?
エイチームは、インターネットを使った多様な技術を駆使し、幅広いビジネスの領域に挑戦し続ける名古屋の総合IT企業です。
そのグループ会社である株式会社エイチームブライズでは、一緒に働く仲間を募集しています!
上記求人をご覧いただき、少しでも興味を持っていただけた方は、まずはチャットでざっくばらんに話をしましょう。
技術的な話だけでなく、私たちが大切にしていることや、お任せしたいお仕事についてなどを詳しくお伝えいたします!
Qiita Jobsよりメッセージお待ちしております!