FLOCSS設計を試した時のいろいろ

CSSの設計でFLOCSSというもの知り、試してみました。

FLOCSSとは

  • OOCSS、BEM、SMACCS、MCSSなどの既存のコンセプトを取り入れたCSSの設計案。
  • 命名規則はBEMの設計思想を元にしたMindBEMdingを採用。
  • Foundation、Layout、Objectと呼ばれる3つの大レイヤーがある。
  • 大レイヤーの1つであるObjectはComponent、Project、Utilityの3つの子レイヤーで構成される。
  • レイヤーには記述順があり、それぞれ役割がある。
  • モジュールに対しプレフィックス(接頭辞)をつける。
  • 原則としてモジュール間のカスケーディング、他のモジュールを親とするセレクタを用いたカスケーディングは禁止している。
  • モジュール内で完結するカスケーディング、複数のセレクタを用いることは許容されている。

レイヤー構成

  • Foundation - リセット、ベースデザインのレイヤー。
  • Layout - ヘッダーやフッターなどのレイアウトレイヤー。
  • Object
    • Component - 最低限の機能を持ったボタンなどのレイヤー。
    • Project - 記事やカードなどの固有なビジュアルパターンのレイヤー。
    • Utility - マージンやパディングなどの調整用のレイヤー。

レイヤーの持つ役割

Foundation

初期化や基本的なスタイルを記述するレイヤー。

/* ==========================================================================
   Foundation
   ========================================================================== */

/* Reset
   ----------------------------------------------------------------- */

html,body {
  margin: 0;
  padding: 0;
}

/* Base
   ----------------------------------------------------------------- */

body {
  font-size: 14px;
}

Layout

ヘッダーやフッターといった大枠のスタイルを記述するレイヤー。Layoutはプレフィックスとして「l-」を記述。

/* ==========================================================================
   Layout
   ========================================================================== */

.l-header {
  background: red;
}

.l-footer {
  background: green;
}

Object

Component、Project、Utilityの子レイヤーを内部に持つ。

Component

最低限の機能を持ったものとして定義される機能単位で分割したモジュールのスタイル。Componentはプレフィックスとして「c-」を記述。

/* ==========================================================================
   Object
   ========================================================================== */

/* Component
   ----------------------------------------------------------------- */

.c-button {
  display: block;
}

Project

Projectは固有のビジュアルパターンで、Componentに該当しない要素によって構成されるスタイル。Projectはプレフィックスとして「p-」を記述。

/* ==========================================================================
   Object
   ========================================================================== */

/* Project
   ----------------------------------------------------------------- */

.p-article {
  background: #EFEFEF;
}

Utility

Component、Projectで解決することが難しい、または適切では無いといった調整用のスタイル。Utilityはプレフィックスとして「u-」を記述。

/* ==========================================================================
   Object
   ========================================================================== */

/* Utility
   ----------------------------------------------------------------- */

.u-mt5 {
  margin-top: 5px;
}

.u-pt5 {
  padding-top: 5px;
}

命名規則はBEMによるMindBEMding

モジュールはBlock、Element、Modifierといったように分けられ、すべて存在する場合、「Block__Element--Modifier」となる。

<div class="block">
    <div class="block__element"></div>
</div>

<!-- modifierがある場合 -->
<div class="block block--modifier">
    <div class="block__element block__element--modifier"></div>
</div>

ComponentでのMindBEMding

HTML

<ul class="c-breadcrumbs">
    <li class="c-breadcrumbs__breadcrumb">
        <a href="#" class="c-breadcrumbs__breadcrumb__link">
            トップ
        </a>
    </li>
    <li class="c-breadcrumbs__breadcrumb">
        <a href="#" class="c-breadcrumbs__breadcrumb__link">
            階層2
        </a>
    </li>
    <li class="c-breadcrumbs__breadcrumb">
        カレント
    </li>
</ul>

CSS

.c-breadcrumbs {
  margin-bottom: 5px;
}

.c-breadcrumbs__breadcrumb {
  display: inline-block;
  vertical-align: top;
  margin-right: 10px;
}

.c-breadcrumbs__breadcrumb__link {
  color: #333;
}

ComponentでModifierがある場合

Modifierは「--modifier」として、「--(ハイフン)」を2つ記述。別パターンのデザインがある場合にModifierを作成。

HTML

<ul class="c-breadcrumbs c-breadcrumbs--modifier">
    <li class="c-breadcrumbs__breadcrumb c-breadcrumbs__breadcrumb--modifier">
        <a href="#" class="c-breadcrumbs__breadcrumb__link c-breadcrumbs__breadcrumb__link--modifier">
            トップ
        </a>
    </li>
    <li class="c-breadcrumbs__breadcrumb c-breadcrumbs--modifier">
        <a href="#" class="c-breadcrumbs__breadcrumb__link c-breadcrumbs__breadcrumb--modifier">
            階層2
        </a>
    </li>
    <li class="c-breadcrumbs__breadcrumb c-breadcrumbs__breadcrumb--modifier">
        カレント
    </li>
</ul>

Modifierのスタイルは別パターンのデザインがある場合に作成されるので、デフォルトのBlockやElement下に記述。

CSS

.c-breadcrumbs {
  margin-bottom: 5px;
}

.c-breadcrumbs--modifier {
  background: #EFEFEF;
}

.c-breadcrumbs__breadcrumb {
  display: inline-block;
  vertical-align: top;
  margin-right: 10px;
}

.c-breadcrumbs__breadcrumb--modifier {
  font-size: 18px;
}

.c-breadcrumbs__breadcrumb__link {
  color: #333;
}

.c-breadcrumbs__breadcrumb__link--modifier {
  color: #666;
}

ProjectでのMindBEMding

HTML

<article class="p-article">
    <h1 class="p-article__title">見出し</h1>
    <time class="p-article__date">2XXX/XX/XX</time>
    <p class="p-article__text">テキスト</p>
</article>

CSS

.p-article {
  width: 1000px;
  padding: 20px;
  border: 1px solid #ccc;
}

.p-article__title {
  margin-bottom: 20px;
  font-weight: bold;
}

.p-article__date {
  display: block;
  text-align: right;
}

.p-article__text {
  font-size: 14px;
}

ProjectでModifierがある場合

Modifierは「--modifier」として、「--(ハイフン)」を2つ記述。別パターンのデザインがある場合にModifierを作成。

HTML

<article class="p-article p-article--modifier">
    <h1 class="p-article__title p-article__title--modifier">タイトル</h1>
    <time class="p-article__date p-article__date--modifier">2XXX/XX/XX</time>
    <p class="p-article__text p-article__text--modifier">テキスト</p>
</article>

Modifierのスタイルは別パターンのデザインがある場合に作成されるので、デフォルトのBlockやElement下に記述。

CSS

.p-article {
  width: 500px;
  padding: 20px;
  border: 1px solid #ccc;
}

.p-article-modifier {
  background: #EFEFEF;
}

.p-article__title {
  margin-bottom: 20px;
  font-weight: bold;
}

.p-article__title--modifier {
  margin-bottom: 40px;
}

.p-article__date {
  display: block;
  text-align: right;
}

.p-article__date--modifier {
  text-align: left;
}

.p-article__text {
  font-size: 14px;
}

.p-article__text--modifier {
  font-size: 20px;
}

モジュールに対しプレフィックス(接頭辞)をつける。

役割を明確にするため、レイヤーの各モジュールにプレフィックスをつける。

  • Layout:.l-*
  • Component:.c-*
  • Project:.p-*
  • Utility:.u-*

スタイルの詳細度を高めないように注意する

スタイルの詳細度を高めないという決まりごとがあるので、セレクタを用いたカスケーディングは行わない。

/* ダメな例 */
.p-article div {
  font-weight: bold;
  font-size: 14px;
}

/* よい例 */
.p-article__division {
  font-weight: bold;
  font-size: 14px;
}

レイヤーの順番

FLOCSSはレイヤー順が決まっているので、Foundationから順に記述していくと下記のようになる。

/* ==========================================================================
   Foundation
   ========================================================================== */

/* Reset
   ----------------------------------------------------------------- */

html,body {
  margin: 0;
  padding: 0;
}

/* Base
   ----------------------------------------------------------------- */

body {
  font-size: 14px;
}

/* ==========================================================================
   Layout
   ========================================================================== */

.l-header {
  background: red;
}

.l-footer {
  background: green;
}

/* ==========================================================================
   Object
   ========================================================================== */

/* Component
   ----------------------------------------------------------------- */

.c-button {
  display: block;
}

/* Project
   ----------------------------------------------------------------- */

.p-article {
  background: #EFEFEF;
}

/* Utility
   ----------------------------------------------------------------- */

.u-mt5 {
  margin-top: 5px;
}

.u-pt5 {
  padding-top: 5px;
}

一番下に記述される調整用の「Utility」が最も強いことになる。Foundation(Reset、Base)、 Layout、Object(Component、Project、Utility)の記述順は変えない。

Sass(Scss)の利用

FLOCSSはCSSの拡張であるSass(Scss)と相性がよい様なので、下記のように利用してみました。

ディレクトリ

scssというフォルダ内にscssファイルを設置しています。

scss
|   style.scss
|
+---foundation
|       _base.scss
|       _mixin.scss
|       _reset.scss
|
+---layout
|       _footer.scss
|       _header.scss
|
\---object
    +---component
    |       _breadcrumb.scss
    |       _button.scss
    |       _input.scss
    |
    +---project
    |       _article.scss
    |       _card.scss
    |
    \---utility
            _margin.scss
            _padding.scss

分割したscssファイルをimport

scssフォルダ直下にある「style.scss」ファイルに、各レイヤーのscssファイルをimportして、コンパイル時に結合するようにしています。

/* ==========================================================================
 Foundation
============================================================================*/

@import "foundation/_reset.scss";
@import "foundation/**";

/* ==========================================================================
 layout
============================================================================*/

@import "layout/**";

/* ==========================================================================
 object
============================================================================*/

/* Component
   ----------------------------------------------------------------- */
@import "object/component/**";

/* Project
   ----------------------------------------------------------------- */
@import "object/project/**";

/* Utility
   ----------------------------------------------------------------- */
@import "object/utility/**";

globプラグインで複数のSass(Scss)ファイルをimportする

Sass(Scss)ファイルの複数のimportは「gulp-sass-glob」というプラグインを利用すると楽なので、gulpというタスクランナーを利用して、下記のように記述して運用しました。ignorePathsで「foundation/reset.scss」を除外している理由は、 通常globでのimportはアルファベット順に読み込まれるので一旦除外し、「foundation/reset.scss」として上記の「style.scss」内にある「@import "foundation/**";」の上に、「@import "foundation/_reset.scss";」として手動で記述し、一番最初にリセット用のscssを読み込ませています。

gulpfile.js

// プラグインをインストール後、読み込み
var sassGlob = require('gulp-sass-glob');

// タスク
gulp.task('scss', function() {
  return gulp.src(paths.scss + '**/*.scss')
  .pipe(sassGlob({
    ignorePaths: [
      'foundation/_reset.scss'
    ]
  }))
});

実際には「gulp-sass-glob」だけでなく、「gulp-sass」などのプラグインも読み込んでいます。globを利用すると、「**/」でそのフォルダ内に作成されたファイルは自動でimportされるので便利です。

ComponentとProjectのどちらに振り分けるのか

FLOCSSで設計するにあたり、一番頭を悩ませるのが、デザインのプロパティをComponentに振り分けるのか、Projectに振り分けるのか、といったことになると思います。

そこで、一つの例として、下記のようなデザインで2つのProjectがある場合を考えてみます。

CSS

.p-card__thumb {
  display: block;
  border-radius: 6px;
  border: 1px solid #333;
  width: 100px;
  height: 100px;
}

.p-photo__thumb {
  display: block;
  border-radius: 6px;
  border: 1px solid #333;
  width: 200px;
  height: 200px;
}

上記のCSSからComponentを切り出してみます。

ProjectからComponentを切り出し

/* Projectから切り出されたComponent */
.c-thumb {
  display: block;
  border-radius: 6px;
}

/* 固有なビジュアルパターンのProject */
.p-card__thumb {
  border: 1px solid #333;
  width: 100px;
  height: 100px;
}

.p-photo__thumb {
  border: 1px solid #333;
  width: 200px;
  height: 200px;
}

ProjectからComponentとして、「display: block;」と「border-radius: 6px;」を切り出しました。

「border: 1px solid #ccc;」もComponentである「c-thumb」に振り分けたいところですが、Componentの定義としては

出来る限り、最低限の機能を持ったものとして定義されるべきであり、それ自体が固有の幅や色などの特色を持つことは避けるのが望ましい

とあるので、装飾とみなされる「border: 1px solid #ccc;」はComponentには振り分けません。これはボーダーの太さや色が変わることを想定して、Projectである「p-」に記述するべきプロパティとなります。 ですが、「border: 1px solid #ccc;」が太さも色も変わらずに、サムネイルのデザインとして必ず存在するのであれば、「Component」である「c-thumb」に「border: 1px solid #ccc;」を記述しても問題ないはずです。

上記の例はProjectから切り出されたComponentと言えると思います。 個人的な解釈になるのかもしれませんが、Componentは最低限の機能を持ったボタンとして始めからComponentとして作成されたプロパティと、共通のプロパティとしてProject内から切り出されたComponent、といったように2つのケースが存在すると考えています。

また、この場合のHTMLに記述するクラスは下記のようになります。

HTML

<div class="p-card">
    <div class="c-thumb p-card__thumb">
        カードのサムネイル
    </div>
</div>
<div class="p-photo">
    <div class="c-thumb p-photo__thumb">
        写真のサムネイル
    </div>
</div>

ComponentとProjectによるマルチクラスになり、記述する順番としてはレイヤー順に従った場合、「c-」のComponentが「p-」のProjectの前にきます。

FLOCSSで悩んだこと

FLOCSSでCSSの設計を行うにあたり、一番難しく悩んだことは、ProjectとComponentの関係とその理解、デザインのプロパティをComponentかProject、一体どちらに振り分けるのか、といったことでした。

ProjectとComponentの関係としては、ボタンはComponentに適しているので、article要素(Project)の中にa要素のボタン(Component)が設置されることもありますし、最低限の機能を持つという性質から、「class="c-* p-*"」といったようにComponentとProjectによるマルチクラスとして記述されることもあります。

ProjectとComponentの振り分けとしては、ボタンなど、最初から最小限の機能を持ったComponentとして作成される場合もあれば、Projectに共通のプロパティがあり、Componentに切り出される場合があります。ですが時間が経過し、デザインに変更が生じてComponentに切り出したプロパティが共通のプロパティではなくなり、固有なビジュアルパターンであるProjectのプロパティになったり、またはそのModifierになる、といったこともありえます。

FLOCSSで設計してよかったこと

だいたいCSSが破綻していくのは規則性がないカスケーディングや、よく検討せずにセレクタを使用したがゆえの詳細度の高まりに苦労する、といったことが大きいのですが、FLOCSSで設計することによりそういったことが随分減りました。スタイルの再利用、保守性やメンテナンスにも有用だと感じました。

また、プロパティに関して、そのデザインにとって固有なものか共通なものか、といったことを意識してコーディングできるようになったと思います。

最後に

FLOCSS設計はある程度の学習コストがかかると思います。まだ個人でしか試せていませんが、真価を発揮するのはおそらくチームやグループでの活用だと思いました。

最後に、ここまで読んでいただきありがとうございます。

関連記事

この記事へのコメント

まだコメントはありません
+1
18
@aBcSiwClZ6Xycv2hの技術ブログ
このエントリーをはてなブックマークに追加