Help us understand the problem. What is going on with this article?

脱・CSS無法地帯。FLOCSSで指針のある設計を。

More than 3 years have passed since last update.

FLOCSSの導入事例の共有

2017年の6月にリニューアルした転職ナビ
最も大変だった事の一つはFLOCSSの導入でした。
FLOCSSは

  • 命名規則にMindBEMdingを採用
  • ファイル・ディレクトリ構成を定義
  • カスケーディングと詳細度の管理方法にも言及

という特徴をもった、CSS設計指針です。

FLOCSSのドキュメントは世に数有るけれども導入事例や知見がもう少し欲しかったなと。
こちらの記事では転職ナビがFLOCSSを導入した時のお話をさせていただきます。

そもそも「CSS設計ってなんやねん」って方は、手前味噌ではございますが、よろしければこちらの記事をどうぞ。
CSS設計を勉強するならまずこれを見たら良いかも

CSS設計で解決したかった課題

そもそも転職ナビのCSS設計を再定義することで解決したかった課題は2つあります。

オレオレになりがちな命名規則

プレフィックス

.mod-btn {}
.v3-btn {}
.brand-name-btn {}
.home-btn {}

一般的に言えることだと思うのですが、フロントエンドの文化的にCSSではこういった数多くのプレフィックスが用いられてきました。
これらプレフィックスも適切に運用するなら間違いだと言えませんが、どうしても運用の背景、文脈が理解されにくく、積極的に導入して運用するのは難しいと感じています。

命名方針

.blue-btn {}
.primary-btn {}
.search-btn {}

例えば、ひとつのボタンを命名する際に悩んだ経験はありませんか?
blue(見た目)、primary(デザインルール)、search(運用ルール)どのルールで命名すべきか。
CSSフレームワークの命名を見ると、primary(デザインルール)での命名が多い印象があります。
それぞれメリット・デメリットがあると思いますが、大事なことは作ったクラス名がMECEに分類できることだと思います。
やはり、ルールが定まっていることが大事だと考えています。

オレオレになりがちなディレクトリ構成

増えるファイルに対して、どの粒度でどういった方針でディレクトリを分割するかの指針がない状態でした。
以下は参考までにFLOCSS導入前のディレクトリ構成です。

├─module/(いわゆるコンポーネント用ディレクトリ)
│  ├─module.scss(こまかいコンポーネントがとにかく入っている)
│  ├─(30ファイル程度コンポーネント毎にファイルがある状態)
│  ├─
├─hoge/
├─fuga/
├─piyo/
└─application.scss

ここでの問題点は

  • 運用していく中でmoduleディレクトリの中にコンポーネントSCSSファイルを追加していったため、ひとつのディクレクトリが膨れ上がった。
    • また、運用をすすめる中でmoduleディレクトリを分解する方針も立たず。
  • 各SCSSファイルをimportするapplication.scssファイルがあるのですが、同階層にSCSSファイルが多く混在してしまった。

つまり、運用をすすめる上でディレクトリを分解し整理することができておらず、ファイル構成の理解が難しくなってきていました。

そして、FLOCSSを導入することに

以前のPC用CSSでは、曖昧な方針で運用してしまった結果、秩序がない状態になってしまっていました。
そう、とにかくCSSに指針が欲しかったのです。
誰よりも(切実に)私が、、、
そこで、FLOCSSを導入することになったのですが、なぜFLOCSSにしたのか。
CSS設計指針の選定で気をつけたポイントがあります。

  • 命名規則
    • 命名方針について、具体的にルールがあること
    • プレフィックスについてルールを定めていること
  • ディレクトリ構成の方針について、言及している
    • 運用していく中で、新規ファイルをどこに作るべきか判断できること
    • また、ディレクトリを適切に用意することで管理しやすくなること
  • 開発メンバが納得できる
    • 多少の独自ルール(組織の風土やレベルにあったルール)は包含しつつも、開発メンバが共有できる指針
    • 知名度
    • ドキュメントの豊富さ
    • 権威(これを基準にするにはあまり良くないですけど、やっぱり有名だと納得できる部分はありますよね)

その点FLOCSSは最初に説明した

  • 命名規則にMindBEMdingを採用
  • ファイル・ディレクトリ構成を定義
  • カスケーディングと詳細度の管理方法にも言及

これら特徴を持ち、さらに

  • 知名度があり、
  • 日本語ドキュメントや書籍がある。

といった特徴もあります。

FLOCSSとは

ざっくり2つの観点で説明します。
※尚、CSSプリプロセッサであるSCSSを前提としています。

ディレクトリ構成

├──foundation/
├──layout/
└──object/
    ├──component/
    ├──project/
    └──utility/
  • foundation -- Reset.cssなど土台となるCSS群。(変数定義用のvariables.scssもこちらに含めました。)
  • layout -- header, sidebar, footerなどのレイアウト用CSS群
  • object/component -- 再利用できる小さなコンポーネントCSS群
  • object/project -- プロジェクト固有のコンポーネントCSS群(後述しますが、object/componentとの違いがすこしややこしいです)
  • object/utility -- ユーティリティクラスを定義するCSS群

命名規則

MindBEMding

MindBemdingとはBEMをベースにした命名規則です。
コンポーネントを一つの塊、Blockとして捉え、命名の起点はすべてBlockをもとに考えます。
Elementはそのコンポーネントを構成する子要素のことで、
Modifierはバリエーション違いを表します。
以下は簡単なMindeBEMdingで命名されているbuttonコンポーネントの例です。

// Block
.button {}
// Block - Element
.button__text {}
// Block - Modifier
.button--primary {}

プレフィックス

上述したディレクトリ構成に基づくプレフィックスが定義されています。

layout - l-*
component - c-*
project - p-*
utility - u-*

これらが定義されることで、名前空間の衝突が減り開発の安定につながることでしょう。
また、命名からそのクラスの運用ルールが予測できるようになります。

独自ルール(FLOCSSとは異なるローカライズルール)

ComponentとProjectの区別

ここの解釈がFLOCSSの難しいところだと感じています。
とはいえ、運用が始まるとここが主に膨らむ箇所ということは間違いなく、雑ではなく、丁寧に設計したいところです。
ComponentとProjectの使い分けはどうしたらいいのでしょう。
大本の定義は、、

  1. Component 再利用できるパターンとして、小さな単位のモジュールを定義します。 一般的によく使われるパターンであり、例えばBootstrapのComponentカテゴリなどに見られるbuttonなどが該当します。 出来る限り、最低限の機能を持ったものとして定義されるべきであり、それ自体が固有の幅や色などの特色を持つことは避けるのが望ましいです。
  2. Project プロジェクト固有のパターンであり、いくつかのComponentと、それに該当しない要素によって構成されるものを定義します。 例えば、記事一覧や、ユーザープロフィール、画像ギャラリーなどコンテンツを構成する要素などが該当します。

hiloki/flocssより引用
https://github.com/hiloki/flocss

とあります。
私なりの解釈だと上述した、btn-blue,btn-primaryがComponentになり、btn-searchのようなプロジェクトで使用される、文脈が含まれるようなUIの場合がProjectなのかなと。
あとは、より複雑性の増したUIも、この定義だとProjectに含まれると思います。
そうは考えたのですが、開発の速度や難易度を考慮して、ここは定義を変更して導入しました。
Atomic Designでいう、AtomsをComponent、Molecules等Atoms以外をProjectとしました。
再利用性の高い粒度の小さいコンポーネントがComponentのイメージです。
そして、極力見た目に基づく分類でCSSの命名を統一しました。

Utilityクラスは控えめに

mb30といった命名はしないようにしました。
とても便利ではあるのですが、style属性との違いが曖昧であると感じているからです。
また、ユーティリティクラスを導入していて、mb30があったとき

.mb30 {
    margin-bottom: 30px;
}

btn-areaにmarginをつけたい場合、このようにマルチクラスとしてmb30を用いるべきなのか、

<style>
.btn-area {
    background-color: #3d70bb;
    color: #fff;
    padding: 10px;
}
</style>
<div class="btn-area mb30">button</div>

もしくは、btn-areaにmargin-bottomを定義するのか。

<style>
.btn-area {
    background-color: #3d70bb;
    color: #fff;
    padding: 10px;
    margin-bottom: 30px;
}
</style>
<div class="btn-area"></div>

このような場合Utilityクラスを使うべきかどうかの判断が難しくなります。
とはいえ、Utilityクラスは便利なので、必要です。
したがって、以下のような使用の判断が容易な命名のみ許容し、Utilityクラスの使用は控えめにするようにしました。

.u-container {}
.u-vertical-gutter {}

ModifierはBEMルール

MindBEMdingでいうと
Modifierはbtn--smallといったようにします。
一方、BEMではbtn--size_smallというようにModifierをkey_valueで表します。

example
//MindBEMding
.btn--small {}
//BEM
.btn-text_small {}

Modifierに関してはMindBEMdingではなく、BEMの考え方を採用しました。
というのも、導入前(リニューアル前)のボタンはマルチクラスで設計しており、全て使用されてはいないですが、可能なビジュアルの組み合わせはあまりにも多く(7800通り)あり、ボタンのバリエーションを増やすCSSクラスを追加するたびに1000パターン程度増えるということになっていました。
Modifierをkey_valueで命名する方が多様なビジュアルを表すには都合が良かったからです。

Element、Modifierの数

それぞれElement、Modifierを2つ作成しないことにしました。
BEM導入にあたって、ひとつ躓くポイントの一つとしてElementとModifierをどこまで厳密に再現するかではないでしょうか。
例えば、

.modal__header--blue__btn--red__text--small {}

というように、BEMではあまりにもクラス名が長くなるケースがあります。
そこで、Blockに対する子要素を明示できれば、運用上大きく問題は生じないと判断し、ElementとModifierを2つ作らないようにしました。

導入した結果

こういった設計は実際に運用が始まってから良し悪しがわかるものであると思うのですが、実際にリニューアルで構築して良かった点を振り返ります。

  • Block毎にファイルを切ることが当たり前になり、一つのファイルの肥大化がなくなった。
  • modulesディレクトリに全てのコンポーネントがあったのが、ComponentとProjectの2つに分割できた。
  • MindBEMdingを採用することで、どのような親子関係でクラスを使用するかがわかりやすくなった。
  • Compnentは再利用性が高いコンポーネントを定義するため、よりきれいに書く場所という認識がチームに生まれた。
  • Utilityクラスはやっぱり便利。
  • 知名度が高い設計手法であり、開発者間で共通の理解を持てるようになった。
  • また、用語が多く定義されているので、共通の合言葉のようなものができ、意思疎通が若干スムーズになった。
  • オレオレルールが少なくなったことにより、レビュー時にルール遵守をお願いする罪悪感が減った。

導入後の課題

ComponentとProjectの区別

こちらの区別が運用してみてやっぱり難しかったです。

.c-table {
    width: 100%;
    background-color: $grayscale6;
    border-spacing: 0;
}

こういった、tableの場合、他のatomsを含んでいないUIの最小単位と判断しました。
したがって上述したコンポーネントの大小による分類方法で考えると、Componentになります。
ただし、人によって大小は主観が入ってしまうので、ComponentではなくProjectに分類することもあるだろうと感じました。

Element、Modifierの数

Elementの数を減らすようにしましたが、

.p-header__btm-area-btn {}

といった命名が生じました。
定めた運用ルールでは間違いではないのですが、これだと

p-header__btm-area__btn {}

でも良かったのではないかと今でも悩んでいます。

pageディレクトリ

いわゆるshame.cssです。(ちょっと言葉が過激だなと感じていますが)
コンポーネントの幅がページ固有の要件の場合、CSSの分類が非常に難しく、page専用のスタイルを定義するファイルを用意しました。

member.scss
.member-wrapper {
    width: 400px;
    margin: 0 auto;
}

命名方針

極力見た目に基づく命名、つまりblue-btnのようなものを心がけて設計しました。
ただ、Elementに多かったのですが

.p-header__main-text {}

のように見た目だけで分類するのが難しい場面がありました。(デザインルールを含めた命名になってしまった)

銀の弾丸ではない

当然かもしれませんがFLOCSSがあるからCSS設計で悩むことがなくなったとかはないです。
デザインが自由である以上、CSSも自由に設計できるはずで、そこに大きな枠組みを設けたという感覚です。
なので、コーディングルールのように劇的な効果があるわけではないが、ないと困るものといった印象を受けました。

まとめ

いかがでしたでしょうか?
CSSは誰でも簡単に書けるという素晴らしい側面がある一方、無法地帯になりやすい言語だと思います。この文章がそんなCSSに苦戦しているエンジニアの力に少しでもなれたら幸いです。
最後まで読んでいただきありがとうございましたmm

sueshin
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away