FLOCSSを使ってCSSファイルを20,000行から9,000行にした話

More than 1 year has passed since last update.

入社して僕が最初にアサインされたのがこのプロジェクト。
サービスをスタートさせたのは今年の2月。最初は外注でとりあえずサービスを作ることに集中していたらしい...
その結果、どのスタイルがどこに作用するか全く分からないCSSの魔境でした。
これでは簡単なページを追加するにも一苦労。
そこで、20,000行あるCSSファイルのリファクタリングに踏み切りました。

当時の問題

スタートアップのサービスなのでもっと機能を追加したり、変更したりしたいと言う要望は日に日に大きくなっていました。
一方で、実際に機能を作ったとしてもそれを view に反映させるのも日に日に苦しくなっていました。
僕たちを苦しめていた理由は以下の通りです。

  • どこにスタイルが作用しているか分からないので、CSSを安易に変更ができない。
  • 新しい部品を付け足す時にCSSの影響範囲を考慮しなくてはならず、プロダクトのUI変更が困難。
  • CSSが大きくなりすぎてCSSの読み込み時間が長い。

これらの問題を考慮して CSS の設計方法から見直しが急務だと直感しました。
また、その設計方法には「無駄なコードの削除」、「可読性の向上」、「スタイルの統一」ができることが必要だなと思いました。

CSS 設計方法に「FLOCSS」の導入

ググって色々あった設計方法の中で、今回は FLOCSS という設計方法を採用しました。

FLOCSS とは

FLOCSS(フロックス)は、OOCSSやSMACSS、BEM、SuitCSSのコンセプトを取り入れた、モジュラーなアプローチのためのCSS構成案。
MCSSのレイヤー構成にも大きな影響を受けています。
詳しく知りたい方は下記の記事を見てください。

https://github.com/hiloki/flocss

FLOCSS にした理由

CSS設計として SMACSS も候補に上がりましたが以下の理由で FLOCSS を採用しました。

  • SMACSS にはコンポーネントの概念がなく、再利用性が FLOCSS の方が高いと考えられる。
  • SMACSS のような直接要素にスタイルを当てる設計だと、後の仕様変更の時に困りそう。
  • FLOCSSにはBEMの概念が含まれていおり、要素と要素の関係が理解がしやすく可読性が高い。

スタートアップのサービスなので機能の変更や追加がこれからまだまだたくさんあることが容易に想像できました。
なので、再利用性が高く、仕様変更が柔軟な設計方法が一番重要でした。
また、これからチームが大きくなっていくことを考えると、途中から入ってきてくれた人たちでも読める可読性の高さも重要な決め手でした。

FLOCSS + 独自ルール

FLOCSS の Object の認識と命名規則として独自の以下のルールを設けて、可読性を上げることを意識しました。

Component

プロダクトの中で4回以上同じ Object が登場したらそれは Component に分類しました。

Project

プロダクトの中で3回以下の使用頻度の Object に該当します。
主な Project の仕事としては擬似要素のスタイリングや、その partial でしかない color, width, height などのプロパティ設定です。

Utility

Utility ファイルは出回ってるだろうと思って、ググり下記のファイルを見つけました。

https://github.com/ruedap/emma.css/blob/master/emma.css

この Utility を使って Component, Project の配置はほとんど設定できました。
また、スマフォとパソコンでの margin, padding は頻繁に変わるので、自分たちで画面サイズでスタイルが変わる Utility を自作で用意しました。

深い階層のセレクタは使わない

深い階層を許容すると、一つの component, project が肥大化する可能性があるので以下のようなBEMは禁止しました。

 B__E__E
 B__E--M--M
 B--M--M
 B--M__E

マルチクラスを積極的に使う

「スタイルは打ち消しより、付け足し」ということを意識して、マルチクラスを積極的に多用するように心がけました。

例

<a class="c-btn c-btn--default c-btn--lg c-btn--block" href="">
  次へ
</a>

float プロパティの使用方針

float、何回か使わないようにしていきましょうか〜とフワッと話してただけでしたが、ガイドラインとして使わないようにして、display: flex や flexbox を使用することにしました。
理由としては、float はレイアウトに使うべきではないからです。
それは以下の経験則を持って判断しました。

  • float を使うとpcとspでのレイアウトを変更しなくてはいけない場合が出てくる。
  • 対象ブラウザが display: flex が使えるブラウザ。
  • float を使う時より display: flex を使うほうが記述が減る。
  • flexbox でパフォーマンスが改善される。 (https://ics.media/entry/11459)

補足

CSS のリファクタリングに伴って、少し JavaScript, view のリファクタリングもしました。

JavaScript のクラス命名規則

JavaScript のセレクタに使われたいるクラス名はjs-*にして、ElementかUtilityかというのは次のように判断しました。

  • Element: ページ内で一箇所のみに現れ、機能性も変わらないもの。
  • Utility: ページ内で複数の箇所に使われる可能性があり、サイト内での機能性も多様なもの。

Element: js-e-*
Utility: js-u-*
それ以外: js-*

view の仕様統一

一つの機能ごとに section 分け、更にその section の中で partial に分けました。
それを踏まえて partial と FLOCSS の component, project と対応させました。

進め方

  1. 一度、サイトの全ページをプリントアウトしてコンポーネントごとに分類。
  2. 分類したコンポーネントに名前をあらかじめ決めておく。
  3. それをオフィスの壁に貼り付ける。
  4. コンポーネントごとに pivotal の story に登録。

コンポーネントごとに分類

最初はとりあえず目につく箇所から手当たり次第にリファクタリングしていました。
しかし、チームでの作業ではコンポーネントの名前の統一感が失われていたし、作業箇所でコンフリクトを起こしたりと問題が連発しました。
そこで、まず自分たちのサイトを全部プリントアウトしてそれをコンポーネントごとに切り出してみました。
これによって自分たちが倒さなきゃいけない敵の数を確認することができました!!
また、この作業によってFLOCSSを勉強したてだった僕は、「コンポーネントとはどの単位?」っていう疑問を解消できたのも大きな進展でした。

名前をあらかじめ決めておく

foundation, layout で迷うことはないと思いますが、 component, project 単位になると一人ひとりが勝手に判断してしまうと後々困るのは最初の段階でわかったので、切り出したコンポーネントはこの段階で component なのか project なのか、はたまた utility で処理するのかを決めてしまいました。
チームの決まり事として、4回以上同じ object があったら component に分類して、3回以下ならば project に分類しました。

IMG_4422.JPG

しかし、実際にリファクタリングしていく中で、「これは component だ!」とか「これは project でしょ!」のような変更は柔軟に対応しました。
ここでの目的は

  • 名前の統一感。
  • 大まかな component, project の認識の共有。
  • component が project の中のどこの部分で再利用できるかの意思統一。

だったからです。
これは作業していく中で無駄な迷いをなくしてくれて非常に効果的だったと思います。

オフィスの壁に貼り付け

出来上がった object たちをオフィスの壁に張り出してみました。

IMG_4407.JPG

全部で40に分類できました。
プリントアウトした時は漠然としていた感覚がここで可視化できたのでモチベーション的に良かったです。
また、改めて膨大なCSSのコードがこの40に集約できるのかと思うと楽しかったです。(リファクタリングが終了した時は結果的に60の object になってましたけどね。笑)
プログラマーからしたら非常に原始的で面倒な作業である1〜3はこのリファクリングの運命やモチベーションを大きく変えてくれたと思います。
最初、僕も「この作業、イケてないなー」と思って始めましたが、実際にやってみるとこの作業をやる前と後では自分の作業の方向性や効率が雲底の差であることに驚きました。
次回の大きなリファクタリングの時にも是非採用したい手法です!!

pivotal に登録

分類したコンポーネントごとに pivotal へ登録し、タスク管理や進捗管理をしました。
pivotal は story ごとに velocity が設定できるので、初心者の僕は順々に自分のタスクの大きさを上げていけたので良かったです。

モチベーション維持

結局、リファクタリングには8月〜10月の3ヶ月間かかってしまいました。
この3ヶ月はずっとCSSのリファクタリングだったのでモチベーションの維持に相当苦労しました。

やったこと

  • 短期的な目標を持つ為に、開発の朝会で自分の今日終わらせる object を宣言。 (毎日)
  • 長丁場なので、のめり込みすぎないように休憩中やランチでチーム内の会話する。 (毎日)
  • CSS の行数のグラフを作って視覚的に css が減ってること体感する。 (毎日)
  • 慣れたらスピードが上がると決めて、最初は予定通りにいかないことにイラつかないようにする。 (序盤)
  • 最初の頃と比べたら1日でこなせる量が増えてることに自信を一方的に覚える。 (中盤)
  • 終わったらみんなで晩杯屋(立ち飲み屋)にいけるという希望を持つ。 (終盤)
  • 誰も知らない最初に CSS を書いた人のことチームで罵る。 (終盤)

ほとんど精神論ですがこれらのことをチーム内の雑談時に話すことによって、ガス抜き・モチベーションの維持を行っていました。

結果

CSS の行数が20,000行から9,000行になりました。
その結果、CSS ファイルのコンパイル時間が9.0秒だったのが、3.8秒になりました。
これでも十分な結果ですが、僕たちにとって目を見張る結果は開発速度が爆速になったことです!!
今までは新しくボタンを付け加えるなんて、どこかに必ず影響が出ることを覚悟していました。ましてや、ページのレイアウト変更なんて一大プロジェクトだったんですよ...
それが今では、section ごとに綺麗に分かれていて、かつその中が partial に分かれている。その partial には対応した FLOCSS の Object があります。
新しいボタンなんて怖くない!ページのレイアウト変更なんて子供だましのパズルみたいなものさ!
嗚呼!!なんて住みやすい世界なんだ!!!!

ちなみに、完成したサイトはこんな感じです。

https://reform-market.com

今後やりたいこと

float 依存脱却

始まった当初は float を flexbox に置き換えていたが flexbox には主に safari でのバグが多く完全な置き換えは断念しました。
それでも利便性は高いので、とりあえずスタイルの崩れが気にならない箇所では使用しました。
また、大切な入力フォームのような箇所では grid を使用して float に頼らないスタイルを目指しましたがどうしても対応できない箇所は float を使用してしまいました。
今後は flexbox のバグが改善されたら float の一掃を考えたいと思っています。

Atomic Design を検討

Atomic Designは今までのページ単位と違いコンポーネント単位でデザインカンプを作る考え方です。 作ったコンポーネント同士の組み合わせでページを作ります。
Atomic Designはコンポーネントの単位を5つに分けています。 その5つの単位はAtoms(原子)・Molecules(分子)・Organisms(有機体)・Templates(テンプレート)・Pages(ページ)です。

Atomic Design とはざっくり言うと、FLOCSS の component, project よりもっと細かくした Atoms, Molecules を作って使い回すと言う設計方法です。
object を作って行く時に、「この小さい部品、前にも見たなー」みたいな時があって、「これも component なのかなー」みたいなことが散見されました。
Atomic Design を使えばこの問題はもう少し防げたのかなと思います。
また、セレクタの詳細度がより平坦になるようです。これは CSS の可読性を高める意味でも導入の余地ありだと思いました。
しかし、デザイナーの方がページをデザインする時は、当然ページ単位なのでデザインの仕方とコーディング仕方にギャップがあるのが欠点かなと思いました。
毎日フルタイムで働いてくれるデザイナーさんが見つかったら、デザインとコーディングの溝を埋めるのが簡単になるのでその時に検討しようと思っています。

Angular / React 導入

ひとまず、view が気軽にいじれるようになってので、次は view 周りを大々的にいじる時なのかなと思っています。
メンテナンス性を考慮して component 指向の Angular / React 導入を考えています。
あと、プロダクトをエンジニアにとって魅力的なものにするという面でも Angular / React は価値があると思います。
まあ、正直、僕がやりたいだけなんですけどね。笑