はじめに
こんにちは。ZOZOTOWN開発本部フロントエンドの菊地(@hiro0218)です。
現在、ZOZOTOWNではWebフロントエンド技術のリプレイスプロジェクトが進行しています。以前の記事ではCSS in JSの技術選定をした際の背景や課題について紹介しました。
その後、「ZOZO Tech Meetup - Web フロントエンド」でおよそ1年後の状況を簡単に共有させて頂きました。
今回はZOZO Tech Meetupでお話した内容に加えて、CSS in JS導入から2年後の現状を改めて紹介したいと思います。
CSS in JS導入後の運用状況
ZOZOTOWNの開発体制は、Webフロントエンドだけでも5つのチームが存在し、さらに外部の業務委託メンバーも加えると、開発に携わるメンバーは執筆時点でのべ50名を超えています。これだけの多人数で開発をすると、開発環境のオンボーディングのようなイニシャルコストや日々の開発に関する問い合わせ対応は膨大なコストがかかってしまうため、以下のような取り組みを実施しています。
- 開発用ドキュメントの整備
- Stylelintによるコードスタイルの統一
- コードの記述方法に迷いが生じないような仕組み
単純に開発ドキュメントだけ整備するのでは伝達や統制に限界がありますが、細かい指針や推奨事項は、仕組み化していくことで開発者のスキルや経験に依存しない高品質な水準の開発を担保しています。また、イニシャルコストの低減だけではなく、コードレビューの効率化やメンテナンス性の向上も実現できています。
これらの中から、いくつかCSS in JSの運用に関わるものを紹介します。
styledの記法
ZOZOTOWNではCSS in JSのライブラリとしてEmotionを採用しています。
Emotionでstyledの記法は「タグ付きテンプレートリテラル記法(以下、テンプレートリテラル記法)」と「オブジェクトスタイル記法」の2つの記法を利用できます。ZOZOTOWNのフロントエンド開発においては「テンプレートリテラル記法」を推奨しています。
それぞれの記法については、以下の通りです。
// テンプレートリテラル記法 const Section = styled.section` background-color: #333; color: #fff; `;
// オブジェクトスタイル記法 const Section = styled.section({ backgroundColor: "#333", color: "#fff", });
「テンプレートリテラル記法」を推奨した理由としては以下の通りです。
- 従来の CSS(Sass)と同様の記述方法ができる
- 導入当初、CSS in JSを初めて利用するメンバーも多く、書き慣れた従来のCSSの記述にすることで参入コストを少しでも下げたかった
- オブジェクトスタイル記法に比べて、CSSに慣れ親しんだメンバーにとっては直感的であり可読性や保守性が高い
- リプレイス前のCSSの実装を移行しやすい利点がある
- スタイルのネストの記述がしやすい
- 親子関係のスタイルや複雑な構造を表現するためのネスト構造(例:
&:hover
)を直接記述できる
- 親子関係のスタイルや複雑な構造を表現するためのネスト構造(例:
- 複雑なスタイリングの記述がしやすい
- メディアクエリや擬似クラス、擬似要素など、CSSの高度な機能をそのまま利用できる
- CSSの継承やカスケードのルールをそのまま適用できるため、スタイルの一貫性を保ちやすい
- 導入当初、CSS in JSを初めて利用するメンバーも多く、書き慣れた従来のCSSの記述にすることで参入コストを少しでも下げたかった
- リプレイス前の環境と共通設定の Stylelint のルールが利用でき一貫性を保てる
properties-order
系のプラグインなどオブジェクトスタイル記法だと一部動かないものがあった
Visual Studio Codeの拡張機能をレコメンドする
Visual Studio Codeを利用している開発者が多いため、.vscode/extensions.json
ファイルをリポジトリ内に用意して、拡張機能をレコメンドしています。
例えばテンプレートリテラル記法は、エディタが標準ではスタイルとしてシンタックスハイライトをサポートしていないため、vscode-styled-componentsのような拡張を利用します。この拡張はstyled-componentsの拡張機能として提供されていますが、同様のシンタックスを有しているEmotionでも問題なく利用できます。
.vscode/extensions.json
へ以下のように記述をするだけで拡張機能を開発者へレコメンドできます。
# .vscode/extensions.json { "recommendations": [ "styled-components.vscode-styled-components" ] }
情報格差(拡張機能を知っているか)で開発効率に差を生まないようにしたい意図があります。
必要な情報はコンテキストに含める
ThemeProvider
のコンテキストには、端末の判定情報やSassの@mixin
や@function
に相当する関数を渡しています。各コンポーネントごとで関数を呼び出さずにstyled内からアクセスできるようにしています。
以下は、font-weight
に指定する値をfunction
経由で取得している例です。
const Text = styled.span` font-weight: ${({ theme }) => theme.function.fontWeight("bold")}; `; // iOS の Hiragino Sans のウェイトには W3, W6, W8 が含まれるが、`font-weight: bold`を指定すると 700 (W7) と同義になり意図よりも太い表示になる。 // 上記の function を利用すると iOS の場合は`font-wight: 600`の指定になり、それ以外の端末は`font-weight: bold`になる。
スタイリングへの関心事をThemeProvider
に集めることで実装者の迷いを減らしています。
Linterで誘導する
スタイル向けのLinterとしてStylelintを導入しています。
Stylelintはリプレイス以前から導入しており、リプレイス後の環境のルールセットは基本的にそのままリプレイス以前のものを移行しています。
独自のルールとして、先述の「font-weight
にbold
を直接記述しない」というルールがあります。このルールは、開発に参加したてのメンバーだと気付きづらく、またレビューでも指摘が漏れたり、テスト時に発覚してしまったりするといったケースも考えられます。これを事前に気付けるようにdeclaration-property-value-disallowed-list
を利用して、bold
の直接指定をルール上は許可しないようにしています。
// stylelint.config.js { rules: { "declaration-property-value-disallowed-list": { "font-weight": "bold", }, }, }
社内の開発ドキュメントでもbold
指定はfunction
を経由するようにと記載していますが、読み飛ばしや解釈違いもあるため、Linterによって二重で防ぐような処置をしています。
開発者の満足度や意見
開発メンバーに対して実施したアンケートの結果と、直近で行ったヒアリングの内容を共有します。
過去に実施したアンケート結果
導入から1年近く経ったZOZO Tech Meetupに際して、「CSS in JSの使い心地」に関するアンケートを実施しました。
対象:
- リプレイス後の環境でCSS in JSを利用して開発を実施した部署内のフロントエンドエンジニア。
設問(一部抜粋):
- CSS in JSに変わったことで、作業効率はどの程度変わりましたか?
- CSS in JS導入による全体的な満足度を評価してください
- CSS in JSはZOZOTOWNに適していると思いますか?
- CSS in JSを利用して新規に実装されたスタイルの品質はどうですか?
- 社内ドキュメントやインターネット上の情報を利用して開発が滞りなく進められていますか?
- CSS in JS(Emotion)のAPIの使い勝手はどうですか?
- その他、ご意見ご感想があれば記入してください
1. CSS in JSに変わったことで、作業効率はどの程度変わりましたか?
- 大いに向上した: 28.6%
- やや向上した: 57.1%
- 変わらない: 14.3%
- やや低下した: 0%
- 大いに低下した: 0%
2. CSS in JS導入による全体的な満足度を評価してください
- 非常に満足: 14.3%
- やや満足: 71.4%
- 普通: 14.3%
- やや不満: 0%
- 非常に不満: 0%
3. CSS in JSはZOZOTOWNに適していると思いますか?
- 非常に適している: 28.6%
- やや適している: 28.6%
- 普通: 42.9%
- やや適していない: 0%
- 全く適していない: 0%
4. CSS in JSを利用して新規に実装されたスタイルの品質はどうですか?
- 非常に高い: 14.3%
- やや高い: 57.1%
- 普通: 28.6%
- やや低い: 0%
- 非常に低い: 0%
5. 社内ドキュメントやインターネット上の情報を利用して開発が滞りなく進められていますか?
- 非常に満足: 42.9%
- やや満足: 28.6%
- 普通: 28.6%
- やや不満: 0%
- 非常に不満: 0%
6. CSS in JS(Emotion)の API の使い勝手はどうですか?
- 非常に使いやすい: 14.3%
- やや使いやすい: 71.4%
- 普通: 14.3%
- やや使いづらい: 0%
- 非常に使いづらい: 0%
7. その他、ご意見ご感想があれば記入してください
- リプレイス以前の環境でスタイルを新規で書く場合は、webpack用のentryファイルを用意する必要があり、それに比べて初期設定が簡単になりスタイルの記述までの作業が減った
- CSS in JS(Emotion)の使い勝手は非常に良い
- CSS in JSに不慣れなメンバーでも参入が容易だった
- CSS in JSを利用することでクラス名管理の問題などが解消された
- (Emotionの)日本語解説が少ないため、高度な利用例(例:ThemeProviderにおけるThemeのマージ)に関する情報が不足していると感じた。今後はそのような知見を蓄積しドキュメントを整備する必要がある
アンケートの総括
全体的にポジティブな回答が得られました。
CSS in JSライブラリ(Emotion)に対する不満が見られないことから、以下のような理由が考えられました。
- 初めて触れるメンバーでも参入しやすかった(簡単)
- ライブラリの機能性に足りない点や問題点が少なかった
ドキュメントや情報が不足していると感じるメンバーもいるものの、全体的には満足度が高い結果だったと言えます。しかし、今よりも対象になる開発メンバーが少なかった事もあり、当然ながら現状とは状況や結果が異なっている可能性があります。
直近で実施したヒアリング結果
先のアンケートから時間も経過しており、関係するメンバーも増えたため、直近で改めて使用感に関するヒアリングを実施しました。
以下のような回答を得られました。
CSS設計を考える手間が減った
リプレイス以前の環境では、CSSのクラス名の命名ルールにMindBEMding(BEMの派生)を採用していました1。この方法は堅牢な命名を可能にする一方で、適切なクラス名を考える手間も必要でした。CSS in JSの導入により、この手間が大幅に軽減され、コンポーネントの命名を集中して考えられるようになりました。
CSSの変更が意図しない箇所やページにまで影響を与えてしまうことがあり、そのリスクを軽減するために命名規則のルールを設けていました。CSS in JSによって自動的にCSSのスコープが制限され、影響範囲も限られることで、それらの問題が発生しにくくなりました。
コードの可読性が向上した
コンポーネント定義とスタイル定義を同じファイル内に共存できます。これによって、コードが見やすくなり、コード間の移動が減り実装スピードも向上しました。また、レビューも同じ観点でしやすくなりました。
複数の状態を持つコンポーネントの場合でも、コードが整理しやすく、読みやすさが向上したと感じています。
JavaScriptとCSSの統合性が向上した
CSS in JSの導入によって、JavaScriptとCSSで共通定義を利用できるようになりました。これにより、細かい設定の一貫性を保つことができました(例:ヘッダーの高さをスタイリング用とスクロール時の位置操作用で同じ値を利用できる)。
スタイルを操作するロジックがJavaScriptで簡潔に記述できるようになり(動的なスタイリングの実装)、複雑なデザイン要件にも対応できるようになりました。
CSS in JSへの課題感
開発者からはポジティブな意見が多く寄せられていますが、現状維持を良しとしているわけではなく、課題感も持って動向を注視しています。
パフォーマンスの懸念
ランタイムCSS in JSを利用していることから、パフォーマンスに関する課題感を持っています。
しかしながら、現状ではパフォーマンス上の問題が顕在化したことはありません。これは、ZOZOTOWN全体におけるリプレイス済みの機能(CSS in JSを利用している箇所)の割合がまだ低いため、問題が表面化していないという可能性も考えられます。
Zero-runtime CSS in JSへのライブラリのリプレイスについては、現時点で具体的な移行計画はありません。技術選定時の評価では、Zero-runtime方式はZOZOTOWNの開発要件を満たせないと判断しており、要件を満たすライブラリが登場しない限りは採用できないと考えています2。
今後、負荷テストなども実施しながら継続的にパフォーマンスを注視していきたいと思います。
可読性の課題
複雑なUIを実装しているとstyledの中で条件分岐が多くなり可読性を下げてしまうケースがあります。
以下のように簡単な分岐でも、条件分岐の記述方法がいくつか考えられます。どのような記述方法にするのが良いのか議論がありました3。
// (1) const Div = styled.div` height: ${({ theme }) => theme.device.isPc ? "55px" : "calc(55 / 375 * 100vw)"}; `; // (2) const Div = styled.div` ${({ theme }) => { return theme.device.isPc ? css` height: 55px; ` : css` height: calc(55 / 375 * 100vw); `; }} `;
上記の記述方法としては、どちらも正しくコーディング規約などで記述方法を制限するようなことはしていません。意見としては以下のようなものが出ており、このような観点も記述の判断材料の1つとすると良いという結論に至りました。
- (1): 他のプロパティが併記されている際にStylelintのソート(
properties-order
)が有効に機能する - (2): PCとSPで大きく定義が異なる場合は可読性が高い
記述方法に厳格な制限を設けていないため、コードの統一性が多少失われることもあります。しかし、過度に複雑な記述(例:多重の条件分岐や特殊な関数の利用)は避けるようにしています。これは、将来的なライブラリのリプレイス時の困難を防ぐためです。そのため、コードレビューやメンバー間での意見交換を通じて、適切な記述方法の意思統一を図っています。
まとめ
本投稿では、CSS in JS導入後の運用について紹介しました。CSS in JSの導入によって、可読性やメンテナンス性の向上といった多くのメリットがもたらされています。
技術選定では「どのようなスキルセットの開発メンバーが関与するか」「選定ライブラリが参入障壁にならないか」を意識していたため、参入障壁になっていないことがアンケートなどの結果から確認でき安心しました。一方で、Runtime CSS in JSのパフォーマンスに関する課題などは存在しているため、今後も技術的な観点で動向を注視していく必要はあると考えています。
同様の技術選定に悩む開発者の参考になれば幸いです。
最後に
ZOZOでは、一緒にサービスを作り上げてくれる方を募集中です。ご興味のある方は、以下のリンクからぜひご応募ください。
- ITCSSを採用して共同開発しやすいCSS設計をZOZOTOWNに導入した話 - ITCSSと命名規則(MindBEMding + 接頭辞)の組み合わせで実現できること↩
- ZOZOTOWN Web フロントエンドリプレイスにおける CSS in JS の技術選定で Emotion を選定した話 - LinariaZero-runtime-CSS-in-JS を検証する↩
- ZOZOTOWN開発本部のフロントエンドエンジニア有志で「スタイル分科会」を発足しており、スタイル周りの技術共有や各チームからの相談を受ける場として活動している。↩