WebNAUT

FLOCSSを扱いきれないあなたに贈る、スリムなCSS設計の話

※この記事は2017年4月7日に執筆された記事です。現在は仕様が異なる可能性があります。


Webの開発をやったことのある方なら誰しも、「CSSって結局どう書くのがベストなの?」という悩みを感じたことがあるでしょう。

一見簡単なCSSですが、一度書き始めるとそのあまりの自由さに、まるで大海原に放り出された赤子のような気分になってしまいますよね。
人生何事も、ある程度制約があったほうがやりやすいものです。

そんなわけで今日はCSSの設計について考えてみましょう。

目次

どんな設計があるの?

CSS設計について調べてみると、OOCSSだとかSMACSSだとかFLOCSSだとか、いろいろな設計思想があることがわかります。

FLOCSSを例に見てみましょう。

概観としては、

の三つがあって、さらにObjectの中に、

があり、これらにCSSを分類して書くという設計用となっています。

FLOCSSの設計に従うことで、

というメリットを得られます。

とはいえ、「ハイハイ、これに従って書けばいいのね」と書き始めたのも束の間、ほとんどの人は思うことでしょう。

「このパーツってComponentとProjectのどっちだ…」

「Utility使いまくらないと全然レイアウト実現できない…」

「Layoutに書くこと少なすぎ…」

多くのWebサイト制作では、FLOCSSのポテンシャルを生かしきれずに、そのメリットがなんだかよくわからないままCSSを書いていくことになってしまいがちです。

相当大規模なプロジェクトならまだしも、ページ数の知れているWebサイトなんかではここまで巨大な設計図を引かなくても、うまいこと組み立てられそうですよね。

ということで、FLOCSSのいいところどりをした、よりスリムな設計「FLOU」を考えてみることにしましょう。

F、L、O、Uの4つに分けよう

基本のアーキテクチャとしては、FoundationLayoutObjectUtilityの4つに分けましょう。

例えばこんな組み方にしたいとき、

それぞれの役割は、図にするとこのようになります。
(分かりやすくするために一部簡略化しています。)

F、L、O、U、の4つが、Webページに必要な要素を過不足なく担当できているのがわかると思います。

具体的なコーディングルールは、下記のような感じです。

Foundation

foundation.scss
html, body, h1, h2, h3, h4, ul, ol, dl, li, dt, dd, p, div, span, img, a, table, tr, th, td {
  margin: 0;
  padding: 0;
  border: 0;
  letter-spacing: 0.5px;
  font-weight: normal;
  font-size: 100%;
  font-family: 'Hiragino Kaku Gothic ProN', 'ヒラギノ角ゴ ProN W3', Meiryo, メイリオ, Osaka, 'MS PGothic', arial, helvetica, sans-serif;
  vertical-align:baseline;
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
  line-height: 1.8;
  word-wrap: break-word;
}

Layout

layout.scss
.l-justify-left {
  display: flex;
  justify-content: flex-start;
}
.l-justify-right {
    display: flex;
    justify-content: flex-end;
}
.l-justify-center {
    display: flex;
    justify-content: center;
}

Layoutにパーツの配置の役割を持たせるのは、「SMACSS」の思想を取り入れているイメージですね。

Object

object.scss
.boxA {
    width: 100px;
    height: 100px;
    color: #ff0000;
}
.boxB {
    width: 200px;
    height: 200px;
    color: #00ff00;
}

Utility

utility.scss
u-mt10 { margint-top: 10px; }
u-mt20 { margint-top: 20px; }
u-mt30 { margint-top: 30px; }

FLOCSSではUtilityクラスはObjectの中の一つとして扱われますが、空きの調整などは基本的にUtilityに任せるルールにし、Objectと同粒度のクラスとしてガンガン使っていきましょう。


この設計を、F、L、O、Uの頭文字をとって、ここでは便宜的にFLOUと呼ぶことにします。

なお、classの命名ルールについては今回は触れませんが、FLOUの設計はMindBEMdingの記法と相性が良いので、こちらも適宜取り入れてみてください。

FLOU設計のメリットは?

さて、このFLOUの設計を使うとどんなハッピーなことがあるのでしょうか。

レイアウトが劇的に楽

まず言えるのが、「モジュールの配置に関していちいちCSSを考える必要がなくなる」ということです。

Layoutに適切なクラスを用意しておくことによって、モジュール(Object)たちを柔軟に、かつスピーディーに配置していくことが可能になります。

例えば、上記のflexboxを使ったLayoutクラスを駆使すれば、下記のように柔軟にモジュールを配置することができます。

ここで使っている.l-justify-leftなどのクラスは、子要素に依存しないレイアウトのクラスとなるので、どんなモジュールに対しても使い回すことができます。
(依存を完全に0にしているわけではありませんが。)

レイアウトだけを担当するクラスを用意しておくというのは、Bootstrapなんかと同じ発想ですね。

旧ブラウザ対応などでflexboxが使えない場合でも、float: left;display: tabel-cell;などを駆使したレイアウトのクラスを用意しておくだけで、マークアップコストが劇的に下がります。

また、配置のためのクラス以外にも、

layout.scss
.l-w25   { width: 25%;   }
.l-w50   { width: 50%;   }
.l-w100p { width: 100%;  }
.l-h100p { height: 100%; }

のように、ラッパーの幅や高さを指定したりするLayoutクラスを用意しておくのも強力ですね。

このように、レイアウトに関する記述をLayoutクラスとして切り出し、使い回すことで、Object内で定義するモジュールを柔軟に配置することができるようになります。

CSSの見通しが良くなる

FLOUを使う二つ目の利点として、「ファイル全体の見通しが良くなる」というものがあります。

例えば、

object.scss
.boxA {
    width: 100px;
    height: 100px;
    color: #ff0000;
    margin-top: 20px; /* ←これに注目 */
}
.boxB {
    width: 200px;
    height: 200px;
    color: #00ff00;
    margin-top: 20px; /* ←これに注目 */
}
.textA {
    color: #ff0000;
    font-weight: bold;
    margin-top: 20px; /* ←これに注目 */
}

とするよりは、

utility.scss
.u-mt20 {
    margin-top: 20px; /* ←これに注目 */
}
object.scss
.boxA {
    width: 100px;
    height: 100px;
    color: #ff0000;
}
.boxB {
    width: 200px;
    height: 200px;
    color: #00ff00;
}
.textA {
    color: #ff0000;
    font-weight: bold;
}

として、各モジュールにhtml上で.u-mt20を付与する方が、全体の見通しが良くなります。

ここでは、単に

ということに加えて

ということも重要です。

上記の前者の例のmargin-top: 20px;は他のモジュールとの関係を定義するのに必要なだけであって、それぞれのモジュールには直接的には関係がない記述ですよね。

このように、モジュール自体が他のモジュールとの関係に関するプロパティを持っていると、想定してなかったモジュールの組み合わせによって、「上の空きが大きすぎる」や「横並びになってくれない」などの不具合が生じかねません。

一方、FLOUの設計であれば、モジュール(Object)と配置(Layout)、調整(Utility)を分けたことで、

ということになるので、仕様の変更に強くなります。

オブジェクトの修正でない、例えばレイアウトの変更や、数px単位の微妙な空き調整なんかは、結局html上でのクラスの付け替え作業になるので、他のページへの影響をケアする必要がなくなるというのも嬉しいところです。

FLOUで書くときのポイントは?

FLOUでは、どの粒度でモジュールを切り出していくのかがポイントになってきます。

理想的な切り出し方は、

  1. できるだけ小さい単位で切り出す
  2. しかし、常にセットで使うものに関しては一つのモジュールにまとめる

というところです。

例えば、こんなパーツを作るとします。

この場合は、フォームとボタンをセットでモジュールとして切り出すのでなく、別々で切り出す方が良いでしょう。

なぜなら、もし「やっぱりこのページだけはフォームとボタンを縦並びに変更したい」となったときに、セットで切り出していた場合は、

ということになりますが、別々で切り出していれば、

という対応だけで済み、モジュールのパターン(今回で言う「フォーム」と「ボタン」)をCSS上で増やすことなくデザインが実現できるからです。

このように、モジュールはできるだけ小さい単位で管理し、配置に関してはLayoutクラスとUtilityクラスに任せることで、CSSの肥大化を抑えることができるのです。

とはいえ、もちろん「このパーツはどんな場面でもセットで使う」と言い切れるものに関しては、セットで管理するのがベターでしょう。

例えば、WebNAUTではトップページや各カテゴリーページなどで使われている記事カードのモジュールのCSSは、一つのセットとして管理しています。

というのが、その理由です。

まとめ

CSSの設計に関しては、SMACSSやFLOCSSなどのオブジェクト指向の設計に従うことで、メンテナンス性に優れたコードを書くことができます。

しかし、どの粒度でオブジェクトを切り出すのか、またオブジェクト以外のクラスはどう扱うかなどはサイトの特性によってまちまちなので、「どんなサイトにでも使える万能な設計手法」というものは存在しません。

そんなときは、今回ご紹介したミニマムな設計である「FLOU」をベースに最適解を模索し、自己流の設計としてアレンジしてみてはいかがでしょうか!