LoginSignup
515
485

More than 1 year has passed since last update.

[CSS設計] 私のためのFLOCSSまとめ

Last updated at Posted at 2019-08-06

FLOCSSとは

「Foundation Layout Object CSS」
OOCSSやBEM、SMACSSのいいとこ取りをしたCSS設計思想。

構造

dartsassに移行しましたので構造を修正しました。

scss/
├─ foundation/
│ ├─ _base.scss
│ ├─ ...
│ ├─ index.scss
├─ global/
│ ├─ mixin/
│ │ ├─ _hover.scss
│ │ ├─ ...
│ │ ├─ index.scss
│ ├─ variable/
│ │ ├─ _color.scss
│ │ ├─ ...
│ │ ├─ index.scss
│ ├─ index.scss
├─ layout/
│ ├─ _header.scss
│ ├─ ...
│ ├─ index.scss
├─ object/
│ ├─ component/
│ │ ├─ _button.scss
│ │ ├─ ...
│ │ ├─ index.scss
│ ├─ project/
│ │ ├─ _header.scss
│ │ ├─ ...
│ │ ├─ index.scss
│ ├─ utility/
│ │ ├─ _color.scss
│ │ ├─ ...
│ │ ├─ index.scss
└─ common.scss

ディレクトリごとに読み込む

@import が非推奨になりdartsassに移行したことで、読み込みには@useを使用します。
後で説明する変数、mixinの globalディレクトリの読み込みには@forwardを使用します。

各ディレクトリに設置したindex.scssにディレクトリ内のSCSSファイルを読み込ませます。

そしてその index.scsscommon.scss に読み込ませます。

読み込みをディレクトリごとにすることで、ファイル追加時に同じディレクトリのindex.scss に記載すればいいだけなのでファイルが膨大になっても、追記しやすく時短になります。

// common.scss
@use "foundation";
@use "layout";
@use "object/component";
@use "object/project";
@use "object/utility";
// object/project/index.scss
// このファイルに追記するだけ
@use "header";
@use "drawer";
@use "nav";
...

:open_file_folder: Global

dartsassに移行したことで、変数、mixinは使用するファイル内に読み込ませる必要があります。

1行で読み込ませるためにglobalディレクトリを追加しました。
dartSassについてはこちらの記事を参考にしてください

:open_file_folder: Foundation

サイト全体のデフォルトスタイルを管理するディレクトリ。

:page_facing_up: reset.scss

ブラウザのデフォルトのスタイルをリセットするcssを定義。
destyle.cssをCDNで読み込んで使用しています。(アプデにすぐ対応できるから)

destyle.cssとは...
デフォルトのスタイリングをほぼ無くすことができるリセットCSS

  • box-sizing: border-box;が含まれている
  • iOSでタップした時のグレー表示も消してくれる
  • marginは基本的に0

抜粋:2020年版!おすすめのリセットCSSまとめ#destylecss | Web Design Trends

:page_facing_up: base.scss

サイトを構成する上で、デザインの基本の下地、土台となるスタイルを定義

  • タグ自体にスタイルを定義
  • :page_facing_up: reset.cssで足りなかったリセットを追加
  • 基本の文字サイズやフォントファミリーなどの追加

:open_file_folder: Layout

各ページを構成する、ヘッダー、メインコンテンツエリア、コンテナ、フッターなどのレイアウトに関するスタイルをエリアごとに管理。

  • 位置など、レイアウトの指定のみ定義
  • 子要素は入れない
  • 自身のデザインは :open_file_folder: Projectで定義する

:page_facing_up: l-wrapper.scss

bodyのすぐ下で、ヘッダーとメインエリアとフッターをかこむ。
コンテンツが少ないときfooterを下寄せに指定するのに必要です。

:page_facing_up: l-header.scss

ヘッダーの位置を定義

:page_facing_up: l-nav.scss)

navは画面構造によって.p-navとして.l-headerのなかに入ることもあるが、.l-という大枠のほうがやりやすければLayoutでOKとする。

:page_facing_up: l-main.scss

メインのコンテンツエリアの共通スタイルを定義

  • ヘッダーのfixed分の相殺や余白など
  • 共通の上下の余白などのみの定義

:page_facing_up: l-container.scss

サイトのメインエリア内のコンテンツ幅、左右の余白の指定

:page_facing_up: l-footer.scss

フッター位置を定義

:open_file_folder: Object

パーツやブロックをすべてObjectと定義。

  • 小さな単位のパーツを :open_file_folder: Component に。
  • Componentが集まったブロックや、大きなエリアは :open_file_folder: Project に。

:open_file_folder: Component

繰り返し使われる小さな単位のパーツを管理。

  • ネストは2回まで
  • marginなど余白は定義しない。あくまでパーツとして扱う

例)
:page_facing_up: c-button.scss
:page_facing_up: c-label.scss
:page_facing_up: c-input.scss

:open_file_folder: Project

いくつかの :open_file_folder: Component と要素によって構成される、大きなブロックやエリアを管理。

  • Componentのように使いまわす。
  • 使い回さないブロックでも分けて管理したい時。(セクションごとに分けるなど)
  • 小さい単位のComponentを集めて、一つのオブジェクトとして扱いたい時
  • Componentとするには大きすぎる時

例)
:page_facing_up: p-card.scss
:page_facing_up: p-first-view.scss
:page_facing_up: p-button-group.scss

:open_file_folder: Utility

  • プロパティ単体での指定を補助する。(font-sizemargin paddingなど)
  • ComponentProjectを無駄に増やしてしまうことを防ぐ
  • あくまで補助としての役割。
  • sp onlypc onlyなどレスポンシブの表示切り替え用クラスなど

:page_facing_up: u-margin.scss
:page_facing_up: u-padding.scss
:page_facing_up: u-color.scss
:page_facing_up: u-text.scss

...

命名規則

プレフィックスをつける

:open_file_folder: layout ならl-:open_file_folder: Componentならc-のように、属してるフォルダ名の{頭文字}+- でプレフィックスを頭につけ、ファイル名だけでもで判断しやすくする(Foundationはリセットや下地が目的なので除く)

:page_facing_up: l-header.scss
:page_facing_up: l-footer.scss
:page_facing_up: c-button.scss
:page_facing_up: p-card.scss

ファイル名 = クラス名

l-header.scssには.l-headerというクラス名を定義

ファイル名、クラス名は省略しない

  • 誰が見てもわかるようにファイル名、クラス名は省略しない
    txtbtnもNG。自分で言葉を作らないこと。(imgはタグ名にあるのでOK)
    ただし、Utilityはクラス名が長くなりがちなので省略可とし、ファイル名は省略しないことで誰が見てもわかるようにする。

ケバブケース

  • linkbuttonのように繋げずlink-buttonのようにケバブケースで書く
  • ページ固有のものはabout-cardのようにする

BEM命名規則MindBEMding

BEM命名規則とはBlock、Element、Modifierに分類して構成される規則。

Block

  • オブジェクト、パーツ、エリアの名前。

Element

  • BLOCKの中の要素たち
  • __でつなげて.Block__Elementとする
  • .Block__Element__ElementはNG。
  • ネストは3階層まで
Element
// NG
<div class="p-about-section">
    ...
    <ul class="p-about-section__list">
        // .Block__Element__ElementはNG
        <li class="p-about-section__list__item">
            <a href="" class="p-about-section__list__item__link">
        </li>
    </ul>
    ...
</div>

// OK
<div class="p-about-section">
    ...
    <ul class="p-about-section__list">
        <li class="p-about-section__list-item">
            // ネストはここまで
            <a href="" class="p-about-section__list-link">
        </li>
    </ul>
    ...
</div>

Modifier

  • オブジェクトの色違いやサイズ違いといった一部の見た目が違うとき
  • 色名やサイズ名を--でつなぎ.Block--Modifierのようなかたちにする。
  • .Block--Modifier--Modifier はNG
  • .Block__Element--Modifier__Element自体の〇〇違いであればOK
例) .Block--Modifier
<!--ボタン-->
<button class="c-button"></button>
<!--ボタンの色違い+サイズ違いモディファイア-->
<button class="c-button c-button--blue c-button--small"></button>

オブジェクト全体のModifierのときは$this: &を使う

  • 子要素のElementにはModifierはかかないでBlockだけModifierにする
  • SCSSの$this: &で子要素のElementにスタイルをあてます
オブジェクト全体のModifier
<div class="p-card p-card--green">
  <div class="p-card__header">
  </div>
  <div class="p-card__body">
  </div>
  ...
</div>
$this: &
.p-card {
    $this: &; // &(p-card)を$this変数にする    
    color: black;
    &__header {
        background-color: gray;
    }
    &__body {
        background-color: white;
    }

    //Modifier
    &--green{
        color: green;  
        #{$this}__header { // .p-card--green .p-card__headerに変換
            background-color: green; 
        }
        #{$this}__body { //.p-card--green .p-card__bodyに変換
            background-color: lightgreen;
        }
    }
}

Element単体のみのModifierもOK

  • オブジェクトの中の一部のElementを右寄せにしたいときなどは.p-card__label--centerのようにElementModifierを指定する
  • 2つ以上のElementが変わる場合は前項のオブジェクト全体のBlockにあてる
オブジェクトのなかの要素だけModifier
<div class="p-card p-card--green">
  <div class="p-card__header">
    <div class="p-card__label p-card__label--center">
    </div>
  </div>
  ...
</div>

このように分けることでいろんなパターンのオブジェクトを作れる

ハイフン1つのクラス名は&-で書かない

  • 下記の例だと__contentを探すときに一瞬混乱するので推奨しない
NGの例
.p-card{
    &__content{
    }
    &__head{
        &-content{ //contentがかぶるのでこの書き方は非推奨
        }
    }
}
OKの例
.p-card{
    &__content{
    }
    &__head{
    }
    &__head-content{ 
    }
}

JavaScriptから参照、操作されるクラス名

キャメルケースcamelCase

JavaScriptに関連するクラス名はキャメルケースcamelCaseでかく

JavaScriptから参照されるクラス名

  • .js-modalToggleのようにプレフィックスにjs-をつけてJavaScriptで操作されることを明示する。
  • .js-のクラス名にはスタイルはあてない
  • JavaScriptでは.js-modalToggleに処理を与える

JavaScriptから操作されるクラス名

  • プレフィックスにis-をつけ、定義する
    • JavaScriptでは.is-clickが操作する処理を与える
  • is-clickのみにスタイルは定義せず、必ず、.c-button.is-clickにスタイルを定義する。(他のオブジェクトに対する.is-clickにスタイルが当たるのを防ぐ)
JavaScript用のクラス
<button class="c-button js-button is-click"></button>
<div class="p-modal js-modalToggle is-click"></div>

同じ.is-clickというクラス名を使っても別々のスタイルを当てることができる。

カスケーディングに気をつける

カスケーディングとは,ある要素のあるプロパティに対する宣言が複数あるとき,宣言の“強さ”の関係を定めて,うち 1 つの宣言だけが有効になるようにするしくみである
Let's begin CSS -- 2.5

別のオブジェクト同士、別のオブジェクトを親とするセレクタを用いたカスケーディングは禁止

つまり下記のようにProjectを親に持つ別のProjectにスタイルを定義するのはだめ。

だめな例

// Component
.c-button {
  ...
}
.c-dialog>.c-button { 
  /*c-dialogを親に持つc-buttonのみスタイルを指定してしまってる!ダメ!*/
  ...
}

// Project
.p-comments {
  ...
}
.p-articles>.p-comments { 
  /*p-articlesを親に持つp-commentsのみスタイルを指定してしまってる!そんな書き方ダメ!*/
  ...
}

理由として、

特定のモジュールに依存することなく、モジュールとして独立して再利用できるべきであり、混在させることによって他の開発者が予想しない挙動になるべきではないためです。
抜粋:hiloki/flocss: CSS organization methodology.

つまり、

  • 汎用的であるべきパーツ(例:c-button)が他のComponent内でしか力を発揮できなくなるのはおかしい
  • 混在することで第三者に、どれがもとのc-buttonのスタイルなのかc-buttonなのにここの下では変わってしまうこのc-buttonを使いたいのにならない、といった混乱を招いてはいけない

ということ。

p-cardの例
<div class="p-card">
  <div class="p-card__header">
  </div>
  <div class="p-card__body">
  </div>
  <div class="p-card__footer">
    <a class="c-button" href="/"></a>
  </div>
</div>

ProjectComponentを上書きできる

Componentの集まりをオブジェクトとしてProjectで管理してる場合、余白などの調整は、ComponentProject__Elementを並列して書くことで上書きOKです

<div class="p-profile c-media">
  <img src="user.jpg" class="c-media__image">
  <div class="c-media__body">...</div>
</div>

こういったときに、c-media__imageの余白をどうしても変えたい!となったら

// c-media.scss内
.c-media__image {
  float: left;
  margin-left: 10px;
}

//p-profile.scss内
.p-profile > .c-media__image { //←ここだめ!
  float: right;
  margin-left: 0; 
  margin-right: 10px;
}

のように変えるのは絶対にNG!
理由は、p-profile内にc-media__imageがあるだけで第三者的には混乱するし、p-profileというObjectが成り立たないし、c-media__imagep-profileのなんなのか、理解しづらいため

そのため必ずクラス名をp-profileElementととし、c-media__imageと並列にかくこと。

良い例
<div class="p-profile c-media">
  <img src="user.jpg" class="p-profile__avatar c-media__image">
  <div class="c-media__body">...</div>
</div>
良い例
// c-media.scss内
.c-media__image {
  float: left;
  margin-left: 10px;
}

//p-profile.scss内
.p-profile > .p-profile__avatar { //←良い
  float: right;
  margin-left: 0; 
  margin-right: 10px;
}

Componentのモディファイア(パターン)を増やすことで対応可能な場合はそこで対応すること。
※ただしモディファイア(パターン)が2つ以上ある場合とする。

ProjectのなかのProject

Projectのなかの別のオブジェクトであるProjectは並列に書きません。
Projectは別のオブジェクトによる変更はできません。
Projectのなかのcomponentのように上書きはしない。

<div class="p-work-section">
  <h2 class="p-work-section__title c-title"></h2>
  <div class="p-work-section__card-list">
      <div class="p-work-card">
        ...
      </div>
  </div>
</div>

ComponentとProjectの違い

人間で言えば、裸んぼの人間が最小単位のモジュールcomponentで、他にネクタイや靴下、スーツといったcomponentがあり、組み合わせてビジネスマンprojectになると考えられます
抜粋:FLOCSSを使ったCSS設計での悩みどころと解決案 - Qiita

  • 小さい単位をComponent
  • Componentの集まりをProject
  • セクションなどの大きいオブジェクトもProjectとして管理します

アイコン付きボタンは.p-button.c-buttonを並列にする

<a class="p-button p-button--icon c-button" href="/">
  <img src="icon-arrow.jpg" class="c-icon c-icon--arrow">
  <span>お問い合わせ</span>
</a>

わかりやすくて気に入ってたんだけど、.c-icon.p-buttonでしか使わないので、この方法はあまり使わなかった。(管理画面のコーディングでは使えるかも)
やってみたら.p-にも.c-にもbuttonがいるのはちょっとムズムズしたので今はあまり使ってません。

結局画像でやるのが楽

結局これでいけちゃう
<a class="c-button c-button--icon" href="/">
  <img src="icon-arrow.jpg" class="c-button--icon__unit">
  <span class="c-button--icon__text">お問い合わせ</span>
</a>

@extendは使用しない

例えば、.c-buttonのModifierをつくるには、下記のように一つのタグへModifierのクラスもつける必要がある

<!--ボタン-->
<button class="c-button"></button>
<!--ボタンの色違いモディファイア-->
<button class="c-button c-button--blue"></button>

@extendc-buttonを継承し、タグへの記載はc-button--blueクラスのみ**にすることが出来る。

SCSS
.c-button {
  ...
}
.c-button--blue {
  @extend .c-button;
  background-color: blue;
}
.c-button--small {
  @extend .c-button;
  background-color: red;
}
CSS
.c-button, .c-button--blue, .c-button--red {
  width: 100px;
}

.c-button--blue {
  background-color: blue;
}
.c-button--small {
  width: 80px;
}

c-button--blueのクラスのみで良いのでクラスの数が減るが、複数のmodifierを指定するときに、結局c-buttonのスタイルを二重指定してしまうことになるので@extendは基本的に使用せず、c-button自体も指定します。

HTML
<a class="c-button--blue" href="">
<a class="c-button--blue c-button--small" href="">

:rolling_eyes:

更新履歴

★2022/04/19 更新
約3年FLOCSSを使い倒し体の一部となった私のためのFLOCSS、編集し直しました。
★2022/08/19
自社のコーディングルール見直しついでに修正しました

参考記事

FLOCSS生みの親による基本ルール

ComponentとProjectの違い

命名規則

BEM

クラス名に迷ったら

515
485
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
515
485